initial
|
|
@ -0,0 +1,97 @@
|
|||
# Basics
|
||||
|
||||
- URL
|
||||
|
||||
|
||||
Source: [https://www.youtube.com/watch?v=AlkDbnbv7dk](https://www.youtube.com/watch?v=AlkDbnbv7dk)
|
||||
|
||||

|
||||
|
||||
Path is like folder and resource is like a file
|
||||
|
||||
IP address: **IP addresses enable websites, servers, and devices**
|
||||
to send and receive data from one another
|
||||
|
||||
- IP and mac
|
||||
|
||||
[https://superuser.com/questions/802421/can-a-website-see-know-my-mac-address-even-if-i-use-a-vpn](https://superuser.com/questions/802421/can-a-website-see-know-my-mac-address-even-if-i-use-a-vpn)
|
||||
|
||||
- OSI
|
||||
|
||||
|
||||
[https://www.youtube.com/watch?v=LANW3m7UgWs](https://www.youtube.com/watch?v=LANW3m7UgWs)
|
||||
|
||||

|
||||
|
||||
# **The OSI model explained in simple terms**
|
||||
|
||||

|
||||
|
||||
[Tom Nagle](https://tomanagle.medium.com/?source=post_page-----2abc3c7adadc--------------------------------)
|
||||
|
||||
·
|
||||
|
||||
Follow
|
||||
|
||||
4 min read
|
||||
|
||||
·
|
||||
|
||||
Jan 19, 2014
|
||||
|
||||
213
|
||||
|
||||
2
|
||||
|
||||
The Open System Interconnection model (OSI) is a seven layer model used to visualize computer networks. The OSI model is often viewed as complicated and many fear having to learn the model. However, the OSI model is an extremely useful tool for development and problem solving. Each of the seven layers goes up in increments of one as it gets closer to the human user. Layer one — the application layer, is closest to the person while layer seven — the physical layer is where the network receives and transmits raw data. The OSI model belongs to the International Organization for Standards (ISO) and is maintained by the identification ISO/IEC 7498–1. In this post, each of the seven layers of the OSI model will be explained in simple terms. The layers will be explained from layer seven to layer one, as this is where the data flow starts.
|
||||
|
||||

|
||||
|
||||
# **The seven layers of the OSI model**
|
||||
|
||||
# **Layer 7 — Application**
|
||||
|
||||
The application layer is where the user inputs data and data is output to the user. The application layer is usually software that is run off the local machine, however this depends on the network architecture. The software could be cloud based, meaning it runs off a server in a remote location and data is transferred over the internet, or the software could be run on a local server. The application layer provides services for email, Telnet and file Transfer for example. An example of the application layer is an internet browser, an FTP client or even Microsoft Word.
|
||||
|
||||
# **Layer 6 — Presentation**
|
||||
|
||||
The presentation layer is where the operating system lies. This operating system could be Windows, OS X, a Unix based operating system or one of the many others available. Where the human user interacts with the application layer described above, the application layer interacts with the presentation layer. This may be done directly, or through a runtime environment such as the Java Runtime Environment (JRE).
|
||||
|
||||
# **Layer 5 — Session**
|
||||
|
||||
The session layer is responsible for creating and maintaining sessions between the operating system on the presentation layer and other, third party machines. For example, when a user is browsing the internet, they are interacting with the application layer, the application layer is interacting with the presentation layer and the session layer allows the operating system to interact with the web server.
|
||||
|
||||
# **Layer 4 — Transport**
|
||||
|
||||
The transport layer is responsible for the logistics of the session. In the example used above, the transport layer would be responsible for determining what and how much information is transferred between the operating system and the web server.
|
||||
|
||||
# **Layer 3 — Network**
|
||||
|
||||
The network layer is where routers operate. A router is a hardware device that forwards packets of information between computers on a network. This is where your IP address comes from and in the example used above, the router is responsible for sending packets of information out into the internet and receiving them. These packets origin and destination is determined by the IP address of your router.
|
||||
|
||||
# **Layer 2 — Data link**
|
||||
|
||||
The data link layer is where switches operate and provides a reliable link between two directly connected nodes. The data link layer is also responsible for detecting and possibly fixing any packet errors that may form on the physical layer. The data link layer is divided into two separate layers, the Media Access Control (MAC) and Logical Link Control (LLC) layers. The MAC layer is responsible for controlling how devices connected to the network gain access. The LLC layer controls error checking, possible fixes and packet synchronization.
|
||||
|
||||
# **Layer 1 — Physical**
|
||||
|
||||
The physical layer is literally the physical hardware that makes up the network. This layer has several major functions:
|
||||
|
||||
- Defining physical specifications
|
||||
- Defining protocols
|
||||
- Defining transmission mode (half duplex & full duplex)
|
||||
- Defining the network’s topology
|
||||
|
||||
Hardware such as the physical components of Ethernet cables and Bluetooth are just some examples of the physical layer.
|
||||
|
||||
# **Purpose of the OSI Model**
|
||||
|
||||
Even after reading a description of each of the seven layers, you may still be confused as to how the OSI model applies to real life networking. It’s commonly misunderstood how a model can be used to solve real-life problems and in some cases, a model may not be the best approach. However, in many aspects of Information & Communications Technology(ICT), a model can be extremely useful and that is the case for the OSI model.
|
||||
|
||||
When first discovering a networking problem, it can be confusing as to where you should start. The OSI model helps you to start figuring out where the problem may reside and therefore, help you to solve the problem. For example, a client’s computer is not able to reach a website. The problem is isolated to one device on the network, so it can be assumed that the problem is likely to be on the application layer. However, after testing you find that the problem still exists when you try a different web browser and so the application layer is ruled out. You then assume that the problem resides on the presentation layer and start looking for faulty settings. After some digging around you find that your client has entered some DNS settings incorrectly and so you then conclude the problem is on the presentation layer.
|
||||
|
||||
You may already be using the OSI model for simple problem solving such as the example above without even realizing it. However, when dealing with large, corporate scale networking a purposeful use of the OSI model can make your job much easier and more enjoyable.
|
||||
|
||||
- socket
|
||||
|
||||

|
||||
|
|
@ -0,0 +1,456 @@
|
|||
# CSS
|
||||
|
||||
- Sass handwritten
|
||||
|
||||
[sass.pdf](../../_resources/sass.pdf)
|
||||
|
||||
[sass.pdf](../../_resources/sass%201.pdf)
|
||||
|
||||
- nth-child pseudoclass
|
||||
|
||||
To select the list for specific number.
|
||||
For eg:
|
||||
|
||||
```html
|
||||
<ul >
|
||||
<li>ty</li>
|
||||
<li>rt</li>
|
||||
<li >as</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
```css
|
||||
ul li:nth-child(2){
|
||||
color: red;
|
||||
}
|
||||
```
|
||||
|
||||
instead of 2, odd or even can be used too.
|
||||
|
||||
Output:
|
||||
|
||||

|
||||
|
||||
also formula can be used like
|
||||
|
||||
```css
|
||||
ul li:nth-child(4n+0){
|
||||
color: red;
|
||||
}
|
||||
```
|
||||
|
||||
all multiples of 4 is selected
|
||||
|
||||
- Caution while using flex
|
||||
|
||||
When using flex layout, for eg to adjust div at center both horizontally and vertically. When we decrease height then upper portion gets out of screen too. To avoid this: set margin as auto for that div.
|
||||
|
||||
```css
|
||||
html,
|
||||
body,
|
||||
#root,
|
||||
.App {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.App {
|
||||
font-family: "Poppins", sans-serif;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.calcBox {
|
||||
margin: auto;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
width: 350px;
|
||||
grid-gap: 1rem;
|
||||
padding: 1rem;
|
||||
background-color: #696969;
|
||||
border: 2px solid black;
|
||||
border-radius: 2px;
|
||||
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
```html
|
||||
<div className="App">
|
||||
<div className="calcBox">
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
- Some important snippets
|
||||
|
||||
minmax application:
|
||||
|
||||
```scss
|
||||
/* Use of minmax */
|
||||
.List {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(100px, 1fr) minmax(200px, 3fr) minmax(
|
||||
150px,
|
||||
2fr
|
||||
) minmax(100px, 1fr) minmax(100px, 1fr) minmax(200px, 3fr);
|
||||
}
|
||||
```
|
||||
|
||||
- For inputButton properly implemented:
|
||||
|
||||
```html
|
||||
<div className="Playlist">
|
||||
<div className="playlistInput">
|
||||
<input
|
||||
className="inputLink"
|
||||
type="text"
|
||||
placeholder="Insert the url of youtube playlist"
|
||||
/>
|
||||
<button>Generate Link</button>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
:root {
|
||||
--deeppink: rgb(255, 0, 104);
|
||||
--deeppinkDark: rgb(230, 0, 94);
|
||||
}
|
||||
|
||||
.Playlist {
|
||||
margin-top: 5rem;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.Playlist .playlistInput {
|
||||
width: 50%;
|
||||
min-width: 300px;
|
||||
border: 4px solid var(--deeppink);
|
||||
border-radius: 3px;
|
||||
overflow-y: hidden;
|
||||
/* padding: 0.5rem; */
|
||||
}
|
||||
|
||||
.playlistInput input {
|
||||
width: 80%;
|
||||
/* height: 100%; */
|
||||
height: 2rem;
|
||||
border: none;
|
||||
outline: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.playlistInput button {
|
||||
width: 20%;
|
||||
height: 3rem;
|
||||
background-color: var(--deeppink);
|
||||
color: white;
|
||||
border: none;
|
||||
/* box-sizing: border-box; */
|
||||
cursor: pointer;
|
||||
transition: all 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
.playlistInput button:hover {
|
||||
background-color: var(--deeppinkDark);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
- Spinner
|
||||
|
||||
```jsx
|
||||
import "./Spinner.css";
|
||||
|
||||
// use 'npm i react-loader-spinner@4.0.0
|
||||
import Loader from "react-loader-spinner";
|
||||
|
||||
// expected props:
|
||||
// visible: boolean ,
|
||||
// classes: string,
|
||||
// color: string,
|
||||
// text: string
|
||||
// https://mhnpd.github.io/react-loader-spinner/docs/category/components/
|
||||
/* text : Radio,Audio,Ball Triangle,Bars,Blocks,Circles With Bar,Circles,Color Ring,Comment,Discuss,
|
||||
DNA,Falling Lines,Fidget Spinner,Grid,Hearts,Hourglass,
|
||||
Infinity Spin,LineWave,MagnifyingGlass,Mutating Dots,Oval,Progress Bar,Puff,
|
||||
RevolvingDot,Rings,Rotating Lines,Rotating Square,
|
||||
Rotating Triangles,Tail Spin,Three Circles,Three Dots,Triangle, Vortex
|
||||
, Watch*/
|
||||
function Spinner(props) {
|
||||
const { visible, text, type } = props;
|
||||
let classes = props.classes || "";
|
||||
const color = props.color || "#fff";
|
||||
let color1 = props.color;
|
||||
// console.log("is spinner visible: ", visible);
|
||||
return (
|
||||
<div className={`Spinner ${classes} ${visible ? "" : "none"}`}>
|
||||
<Loader
|
||||
type={type}
|
||||
color={color}
|
||||
height={50}
|
||||
width={50}
|
||||
timeout={0} //30 secs
|
||||
/>
|
||||
<span style={color1 ? { color: color } : {}} class="Loading_Text">
|
||||
{text}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Spinner;
|
||||
```
|
||||
|
||||
```css
|
||||
.none {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.Spinner .Loading_Text {
|
||||
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
|
||||
}
|
||||
```
|
||||
|
||||
other way
|
||||
```js
|
||||
import "./Spinner.scss";
|
||||
|
||||
function Spinner(props) {
|
||||
const { visible, text, type } = props;
|
||||
let classes = props.classes || "";
|
||||
const color = props.color || "#fff";
|
||||
let color1 = props.color;
|
||||
// console.log("is spinner visible: ", visible);
|
||||
return (
|
||||
// <div className={`Spinner ${classes} ${visible ? "" : "none"}`}>
|
||||
<div className={`spinnerStyle ${classes} ${visible ? "" : "none"}`}>
|
||||
<div className="spinner"></div>
|
||||
<span style={color1 ? { color: color } : {}} class="Loading_Text">
|
||||
{text}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Spinner;
|
||||
|
||||
```
|
||||
|
||||
Spinner.scss
|
||||
```scss
|
||||
.none {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.spinner .Loading_Text {
|
||||
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
border: 8px solid #f3f3f3;
|
||||
border-top: 8px solid #000000;
|
||||
border-radius: 50%;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
.spinnerStyle {
|
||||
display: "flex";
|
||||
justify-content: "center";
|
||||
align-items: "center";
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- Creating pill shaped button
|
||||
|
||||
```css
|
||||
.proceed {
|
||||
margin-top: 1rem;
|
||||
color: white;
|
||||
background-color: black;
|
||||
border: none;
|
||||
border-radius: 9999px;
|
||||
padding: 1rem 0.5rem
|
||||
}
|
||||
```
|
||||
|
||||
set border radius as very long size
|
||||
|
||||
Output:
|
||||
|
||||

|
||||
|
||||
- scroll to specific position with anchor tag
|
||||
|
||||
|
||||
- aspect-ratio
|
||||
|
||||

|
||||
|
||||
- whitespace property
|
||||
|
||||

|
||||
|
||||
- calc()
|
||||
|
||||
## CSS only Approach (If height is known/fixed)
|
||||
|
||||
When you want the middle element to span across entire page vertically, you can use `[calc()](https://developer.mozilla.org/en-US/docs/Web/CSS/calc)` which is introduced in CSS3.
|
||||
|
||||
Assuming we have a *fixed height* `header` and `footer` elements and we want the `section` tag to take entire available vertical height...
|
||||
|
||||
**[Demo](http://jsfiddle.net/WdrDH/)**
|
||||
|
||||
**Assumed markup** and your CSS should be
|
||||
|
||||
```css
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
header {
|
||||
height: 100px;
|
||||
background: grey;
|
||||
}
|
||||
|
||||
section {
|
||||
height: calc(100% - (100px + 150px));
|
||||
/* Adding 100px of header and 150px of footer */
|
||||
background: tomato;
|
||||
}
|
||||
|
||||
footer {
|
||||
height: 150px;
|
||||
background-color: blue;
|
||||
}
|
||||
```
|
||||
|
||||
```html
|
||||
<header>100px</header>
|
||||
<section>Expand me for remaining space</section>
|
||||
<footer>150px</footer>
|
||||
```
|
||||
|
||||
- centralising div
|
||||
|
||||

|
||||
|
||||
Ref:
|
||||
|
||||
[https://www.youtube.com/watch?v=HOM47v73yG8&list=PLBOEc6PNYgCQZl3gDUDtv034yz-kwWkFo&index=3&t=200s](https://www.youtube.com/watch?v=HOM47v73yG8&list=PLBOEc6PNYgCQZl3gDUDtv034yz-kwWkFo&index=3&t=200s)
|
||||
|
||||
[https://www.youtube.com/watch?v=HOM47v73yG8&list=PLBOEc6PNYgCQZl3gDUDtv034yz-kwWkFo&index=3&t=200s](https://www.youtube.com/watch?v=HOM47v73yG8&list=PLBOEc6PNYgCQZl3gDUDtv034yz-kwWkFo&index=3&t=200s)
|
||||
|
||||
when using this method to centralize div, when we decrease screen height then div can go out of screen. To prevent this, use position absolute and
|
||||
|
||||
- For setting dark theme
|
||||
|
||||
We need to invert all colors of the page.
|
||||
|
||||
```html
|
||||
<div style='background-color: white'>
|
||||
hello
|
||||
</div
|
||||
```
|
||||
|
||||
```jsx
|
||||
const css = `html {
|
||||
-webkit-filter: invert(100%);
|
||||
-moz-filter: invert(100%);
|
||||
-o-filter: invert(100%);
|
||||
-ms-filter: invert(100%);
|
||||
}`
|
||||
const head = document.head
|
||||
const style = document.createElement('style')
|
||||
style.type = 'text/css';
|
||||
if (style.styleSheet) {
|
||||
style.styleSheet.cssText = css;
|
||||
} else {
|
||||
style.appendChild(document.createTextNode(css));
|
||||
}
|
||||
head.appendChild(style);
|
||||
```
|
||||
|
||||
[https://thewebdev.info/2021/08/14/how-to-invert-color-on-all-elements-of-a-page-with-javascript/#:~:text=Page with JavaScript-,To invert color on all elements of a page with,100%25](https://thewebdev.info/2021/08/14/how-to-invert-color-on-all-elements-of-a-page-with-javascript/#:~:text=Page%20with%20JavaScript-,To%20invert%20color%20on%20all%20elements%20of%20a%20page%20with,100%25))%20value%20with%20CSS.&text=Then%20we%20can%20invert%20all,%25)%3B%20%7D%60%20const%20head%20%3D%20document.
|
||||
|
||||
- Custom input type=file
|
||||
|
||||
[https://dev.to/faddalibrahim/how-to-create-a-custom-file-upload-button-using-html-css-and-javascript-1c03](https://dev.to/faddalibrahim/how-to-create-a-custom-file-upload-button-using-html-css-and-javascript-1c03)
|
||||
|
||||
- background image
|
||||
|
||||
```jsx
|
||||
body{
|
||||
background-image: url("../images/back2.jpg");
|
||||
|
||||
/* Full height */
|
||||
height: 100%;
|
||||
|
||||
/* Center and scale the image nicely */
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-attachment: fixed;
|
||||
|
||||
margin-left: 0px;
|
||||
|
||||
/*scroll-behavior: smooth !important;*/
|
||||
/*margin-top: 0px;*/
|
||||
}
|
||||
```
|
||||
|
||||
- Useful properties
|
||||
|
||||
Reference: [https://www.youtube.com/watch?v=srzsj3xtHMM](https://www.youtube.com/watch?v=srzsj3xtHMM)
|
||||
|
||||
Clamp:
|
||||
|
||||
```css
|
||||
.container{
|
||||
min-width: 100px;
|
||||
width: 50%;
|
||||
max-width: 200px;
|
||||
}
|
||||
```
|
||||
|
||||
Above can be written as:
|
||||
|
||||
```css
|
||||
.container{
|
||||
width: clamp(100px, 50%, 200px);
|
||||
}
|
||||
```
|
||||
|
||||
Scroll snap:
|
||||
|
||||
while scrolling the current element will be aligned to center
|
||||
|
||||
```css
|
||||
.container{
|
||||
overflow: scroll;
|
||||
scroll-snap-type: x mandatory;
|
||||
}
|
||||
.container .child{
|
||||
scroll-snap-align: center;
|
||||
}
|
||||
```
|
||||
|
||||
order:
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# API
|
||||
|
||||
"genius-lyrics-api": "^3.0.6", react
|
||||
|
|
@ -0,0 +1 @@
|
|||
# Untitled
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# fileLu
|
||||
|
||||
```jsx
|
||||
const HOST='https://filelu.com/api'
|
||||
const FormData=require('form-data')
|
||||
fetch(`${HOST}/upload/server?key=${key}`)
|
||||
.then(res=>res.json())
|
||||
.then(data=>{
|
||||
const {sess_id,result}=data;
|
||||
const formdata=new FormData()
|
||||
formdata.append('sess_id',sess_id)
|
||||
formdata.append('utype','prem')
|
||||
formdata.append('file_0',file,'AliceinChainsThemBones2022Remaster.mp3')
|
||||
|
||||
fetch(result,{
|
||||
method: 'post',
|
||||
body: formdata
|
||||
})
|
||||
.then(res=>res.json())
|
||||
.then(console.log)
|
||||
.catch(console.log)
|
||||
})
|
||||
.catch(console.log )
|
||||
```
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# macros
|
||||
|
||||
[https://www.autohotkey.com/boards/viewtopic.php?t=34355](https://www.autohotkey.com/boards/viewtopic.php?t=34355)
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
# youtube stream itags
|
||||
|
||||
YouTube video stream format codes itags
|
||||
|
||||
[Raw](https://gist.github.com/sidneys/7095afe4da4ae58694d128b1034e01e2/raw/9794b8b7237306d8f9efd8e83ccb08fc9e188432/youtube_format_code_itag_list.md)
|
||||
|
||||
**[youtube_format_code_itag_list.md](https://gist.github.com/sidneys/7095afe4da4ae58694d128b1034e01e2#file-youtube_format_code_itag_list-md)**
|
||||
|
||||
# YouTube video stream format codes
|
||||
|
||||
### Comprehensive list of YouTube format code itags
|
||||
|
||||
| itag Code | Container | Content | Resolution | Bitrate | Range | VR / 3D |
|
||||
| --- | --- | --- | --- | --- | --- | --- |
|
||||
| 5 | flv | audio/video | 240p | - | - | - |
|
||||
| 6 | flv | audio/video | 270p | - | - | - |
|
||||
| 17 | 3gp | audio/video | 144p | - | - | - |
|
||||
| 18 | mp4 | audio/video | 360p | - | - | - |
|
||||
| 22 | mp4 | audio/video | 720p | - | - | - |
|
||||
| 34 | flv | audio/video | 360p | - | - | - |
|
||||
| 35 | flv | audio/video | 480p | - | - | - |
|
||||
| 36 | 3gp | audio/video | 180p | - | - | - |
|
||||
| 37 | mp4 | audio/video | 1080p | - | - | - |
|
||||
| 38 | mp4 | audio/video | 3072p | - | - | - |
|
||||
| 43 | webm | audio/video | 360p | - | - | - |
|
||||
| 44 | webm | audio/video | 480p | - | - | - |
|
||||
| 45 | webm | audio/video | 720p | - | - | - |
|
||||
| 46 | webm | audio/video | 1080p | - | - | - |
|
||||
| 82 | mp4 | audio/video | 360p | - | - | 3D |
|
||||
| 83 | mp4 | audio/video | 480p | - | - | 3D |
|
||||
| 84 | mp4 | audio/video | 720p | - | - | 3D |
|
||||
| 85 | mp4 | audio/video | 1080p | - | - | 3D |
|
||||
| 92 | hls | audio/video | 240p | - | - | 3D |
|
||||
| 93 | hls | audio/video | 360p | - | - | 3D |
|
||||
| 94 | hls | audio/video | 480p | - | - | 3D |
|
||||
| 95 | hls | audio/video | 720p | - | - | 3D |
|
||||
| 96 | hls | audio/video | 1080p | - | - | - |
|
||||
| 100 | webm | audio/video | 360p | - | - | 3D |
|
||||
| 101 | webm | audio/video | 480p | - | - | 3D |
|
||||
| 102 | webm | audio/video | 720p | - | - | 3D |
|
||||
| 132 | hls | audio/video | 240p | - | - | |
|
||||
| 133 | mp4 | video | 240p | - | - | |
|
||||
| 134 | mp4 | video | 360p | - | - | |
|
||||
| 135 | mp4 | video | 480p | - | - | |
|
||||
| 136 | mp4 | video | 720p | - | - | |
|
||||
| 137 | mp4 | video | 1080p | - | - | |
|
||||
| 138 | mp4 | video | 2160p60 | - | - | |
|
||||
| 139 | m4a | audio | - | 48k | - | |
|
||||
| 140 | m4a | audio | - | 128k | - | |
|
||||
| 141 | m4a | audio | - | 256k | - | |
|
||||
| 151 | hls | audio/video | 72p | - | - | |
|
||||
| 160 | mp4 | video | 144p | - | - | |
|
||||
| 167 | webm | video | 360p | - | - | |
|
||||
| 168 | webm | video | 480p | - | - | |
|
||||
| 169 | webm | video | 1080p | - | - | |
|
||||
| 171 | webm | audio | - | 128k | - | |
|
||||
| 218 | webm | video | 480p | - | - | |
|
||||
| 219 | webm | video | 144p | - | - | |
|
||||
| 242 | webm | video | 240p | - | - | |
|
||||
| 243 | webm | video | 360p | - | - | |
|
||||
| 244 | webm | video | 480p | - | - | |
|
||||
| 245 | webm | video | 480p | - | - | |
|
||||
| 246 | webm | video | 480p | - | - | |
|
||||
| 247 | webm | video | 720p | - | - | |
|
||||
| 248 | webm | video | 1080p | - | - | |
|
||||
| 249 | webm | audio | - | 50k | - | |
|
||||
| 250 | webm | audio | - | 70k | - | |
|
||||
| 251 | webm | audio | - | 160k | - | |
|
||||
| 264 | mp4 | video | 1440p | - | - | |
|
||||
| 266 | mp4 | video | 2160p60 | - | - | |
|
||||
| 271 | webm | video | 1440p | - | - | |
|
||||
| 272 | webm | video | 4320p | - | - | |
|
||||
| 278 | webm | video | 144p | - | - | |
|
||||
| 298 | mp4 | video | 720p60 | - | - | |
|
||||
| 299 | mp4 | video | 1080p60 | - | - | |
|
||||
| 302 | webm | video | 720p60 | - | - | |
|
||||
| 303 | webm | video | 1080p60 | - | - | |
|
||||
| 308 | webm | video | 1440p60 | - | - | |
|
||||
| 313 | webm | video | 2160p | - | - | |
|
||||
| 315 | webm | video | 2160p60 | - | - | |
|
||||
| 330 | webm | video | 144p60 | - | hdr | |
|
||||
| 331 | webm | video | 240p60 | - | hdr | |
|
||||
| 332 | webm | video | 360p60 | - | hdr | |
|
||||
| 333 | webm | video | 480p60 | - | hdr | |
|
||||
| 334 | webm | video | 720p60 | - | hdr | |
|
||||
| 335 | webm | video | 1080p60 | - | hdr | |
|
||||
| 336 | webm | video | 1440p60 | - | hdr | |
|
||||
| 337 | webm | video | 2160p60 | - | hdr | |
|
||||
|
||||
```jsx
|
||||
//quality:itag
|
||||
const iTags = {
|
||||
144: "394", //videoonly: 394,132
|
||||
240: "395", //videoonly: 395,133
|
||||
|
||||
360: "18", //videoonly: 396,134 both: 18
|
||||
480: "44", //videoonly: 397, 135 both: 44
|
||||
720: "22", //videoonly: 398, 136 both: 22
|
||||
1080: "37", //videoOnly: 399, 137 both: 37
|
||||
1440: "264",
|
||||
2160: "138",
|
||||
};
|
||||
|
||||
// bitrate : itag
|
||||
const iTagAudio = {
|
||||
128: "140", //mp4
|
||||
64: "250", //webm
|
||||
160: "251", //webm
|
||||
48: "249", //webm
|
||||
};
|
||||
```
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
# GitHub
|
||||
|
||||
[Managing Different Accounts](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/GitHub%20cc67e8c9e0c945a587b473d533a8d80a/Managing%20Different%20Accounts%200b4d3ba72da14c688ca2fc.md)
|
||||
|
||||
[Deploy react site](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/GitHub%20cc67e8c9e0c945a587b473d533a8d80a/Deploy%20react%20site%209aac11a6fab14d8b9165b5927bff7405.md)
|
||||
|
||||
[Git commands](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/GitHub%20cc67e8c9e0c945a587b473d533a8d80a/Git%20commands%206fce236e7a9646bdbbf63290300cf5b4.md)
|
||||
|
||||
[Setting multiple accounts](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/GitHub%20cc67e8c9e0c945a587b473d533a8d80a/Setting%20multiple%20accounts%20734586287c324b9e98996805.md)
|
||||
|
||||
[Project commit ids](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/GitHub%20cc67e8c9e0c945a587b473d533a8d80a/Project%20commit%20ids%206193aa70a9c64e9bb2e25c4e3003847.md)
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
# Deploy react site
|
||||
|
||||
- for vite use this
|
||||
https://dev.to/rashidshamloo/deploying-vite-react-app-to-github-pages-35hf
|
||||
|
||||
From site ‘[https://create-react-app.dev/docs/deployment/](https://create-react-app.dev/docs/deployment/)’
|
||||
|
||||
## [GitHub Pages](https://pages.github.com/)[](https://create-react-app.dev/docs/deployment/#github-pages)
|
||||
|
||||
> Note: this feature is available with react-scripts@0.2.0 and higher.
|
||||
>
|
||||
|
||||
### Step 1: Add `homepage` to `package.json`[](https://create-react-app.dev/docs/deployment/#step-1-add-homepage-to-packagejson)
|
||||
|
||||
**The step below is important!**
|
||||
|
||||
**If you skip it, your app will not deploy correctly.**
|
||||
|
||||
Open your `package.json` and add a `homepage` field for your project:
|
||||
|
||||
`"homepage": "https://myusername.github.io/my-app",`
|
||||
|
||||
or for a GitHub user page:
|
||||
|
||||
`"homepage": "https://myusername.github.io",`
|
||||
|
||||
or for a custom domain page:
|
||||
|
||||
`"homepage": "https://mywebsite.com",`
|
||||
|
||||
Create React App uses the `homepage` field to determine the root URL in the built HTML file.
|
||||
|
||||
### Step 2: Install `gh-pages` and add `deploy` to `scripts` in `package.json`[](https://create-react-app.dev/docs/deployment/#step-2-install-gh-pages-and-add-deploy-to-scripts-in-packagejson)
|
||||
|
||||
Now, whenever you run `npm run build`, you will see a cheat sheet with instructions on how to deploy to GitHub Pages.
|
||||
|
||||
To publish it at [https://myusername.github.io/my-app](https://myusername.github.io/my-app), run:
|
||||
|
||||
`npm install --save gh-pages`Copy
|
||||
|
||||
Alternatively you may use `yarn`:
|
||||
|
||||
`yarn add gh-pages`Copy
|
||||
|
||||
Add the following scripts in your `package.json`:
|
||||
|
||||
```json
|
||||
"scripts": {
|
||||
"predeploy": "npm run build",
|
||||
"deploy": "gh-pages -d build",
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
```
|
||||
|
||||
The `predeploy` script will run automatically before `deploy` is run.
|
||||
|
||||
If you are deploying to a GitHub user page instead of a project page you'll need to make one additional modification:
|
||||
|
||||
1. Tweak your `package.json` scripts to push deployments to **master**:
|
||||
|
||||
```json
|
||||
"scripts": {
|
||||
"predeploy": "npm run build",
|
||||
- "deploy": "gh-pages -d build",
|
||||
+ "deploy": "gh-pages -b master -d build",
|
||||
```
|
||||
|
||||
`"scripts": { "predeploy": "npm run build",- "deploy": "gh-pages -d build",+ "deploy": "gh-pages -b master -d build",`Copy
|
||||
|
||||
### Step 3: Deploy the site by running `npm run deploy`[](https://create-react-app.dev/docs/deployment/#step-3-deploy-the-site-by-running-npm-run-deploy)
|
||||
|
||||
Then run:
|
||||
|
||||
`npm run deploy`
|
||||
|
||||
### Step 4: For a project page, ensure your project’s settings use `gh-pages`[](https://create-react-app.dev/docs/deployment/#step-4-for-a-project-page-ensure-your-projects-settings-use-gh-pages)
|
||||
|
||||
Finally, make sure **GitHub Pages** option in your GitHub project settings is set to use the `gh-pages` branch:
|
||||
|
||||

|
||||
|
||||
### Step 5: Optionally, configure the domain[](https://create-react-app.dev/docs/deployment/#step-5-optionally-configure-the-domain)
|
||||
|
||||
You can configure a custom domain with GitHub Pages by adding a `CNAME` file to the `public/` folder.
|
||||
|
||||
Your CNAME file should look like this:
|
||||
|
||||
`mywebsite.com`
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
# Git commands
|
||||
|
||||
- Resetting local to specific commit
|
||||
|
||||
[https://stackoverflow.com/questions/4114095/how-do-i-revert-a-git-repository-to-a-previous-commit](https://stackoverflow.com/questions/4114095/how-do-i-revert-a-git-repository-to-a-previous-commit)
|
||||
|
||||
`git reset --hard <commidId> && git clean -f`
|
||||
|
||||
or a safer
|
||||
|
||||
`git clean -i`
|
||||
|
||||
commit id:
|
||||
|
||||

|
||||
|
||||
Use `git log` for commit id.
|
||||
|
||||
### Reverting Working Copy to Most Recent Commit
|
||||
|
||||
To revert to the previous commit, ignoring any changes:
|
||||
|
||||
```bash
|
||||
git reset --hard HEAD
|
||||
```
|
||||
|
||||
where HEAD is the last commit in your current branch
|
||||
|
||||
### Reverting The Working Copy to an Older Commit
|
||||
|
||||
To revert to a commit that's older than the most recent commit:
|
||||
|
||||
```bash
|
||||
# Resets index to former commit; replace '56e05fced' with your commit code
|
||||
git reset 56e05fced
|
||||
|
||||
# Moves pointer back to previous HEAD
|
||||
git reset --soft HEAD@{1}
|
||||
|
||||
git commit -m "Revert to 56e05fced"
|
||||
|
||||
# Updates working copy to reflect the new commit
|
||||
git reset --hard
|
||||
|
||||
# Push your changes to respective branch
|
||||
git push -f
|
||||
```
|
||||
|
||||
save modifications before resetting:
|
||||
|
||||
```bash
|
||||
# Alternatively, if there's work to keep:
|
||||
git stash
|
||||
git reset --hard 0d1d7fc32
|
||||
git stash pop
|
||||
# This saves the modifications, then reapplies that patch after resetting.
|
||||
# You could get merge conflicts, if you've modified things which were
|
||||
# changed since the commit you reset to.
|
||||
```
|
||||
|
||||
To revert changes after git push use revert instead of reset —hard
|
||||
|
||||
`git revert <commit_hash>`
|
||||
|
||||
or simply use below after using reset —hard
|
||||
|
||||
`git push -f origin main`
|
||||
|
||||
do not use —force, this will make all your coworkers hate you, use —force-with-lease, this will only allow you to push the code if there are no conflicting changes with the current parent branch
|
||||
|
||||
- Branches
|
||||
|
||||
[https://www.geeksforgeeks.org/how-to-set-upstream-branch-on-git/](https://www.geeksforgeeks.org/how-to-set-upstream-branch-on-git/)
|
||||
|
||||

|
||||
|
||||

|
||||
for adding remote url
|
||||
`git remote add <name> <url>`
|
||||
then
|
||||
`git push --set-upstream <name> master`
|
||||
PS C:\Users\harsh\Videos\imp\react\github\test1> `git branch main -u origin/main`
|
||||
Branch 'main' set up to track remote branch 'main' from 'origin'.*
|
||||
|
||||
*PS C:\Users\harsh\Videos\imp\react\github\test1> `git branch test -u origin/test`
|
||||
Branch 'test' set up to track remote branch 'test' from 'origin'.
|
||||
|
||||
`git push --set-upstream origin <branch name>`
|
||||
to show remote git details like url and all that
|
||||
`git remote show origin` or `git remote -v` (to see only url)
|
||||
To edit current url
|
||||
`git remote set-url origin git@bitbucket.org:tutorials/tutorials.git`
|
||||
|
||||
### **Merging other branch to main:**
|
||||
|
||||
Make sure first you update your **development** branch with master to resolve conflicts issue(if there are any):
|
||||
|
||||
```bash
|
||||
git checkout main
|
||||
git pull origin main
|
||||
git checkout development
|
||||
git merge main
|
||||
|
||||
```
|
||||
|
||||
Now see if master branch is merged without any conflict, if there's any conflict then you'll have to resolve them. Once you're done with that, you can:
|
||||
|
||||
```bash
|
||||
git checkout main
|
||||
git merge development
|
||||
git push origin main
|
||||
```
|
||||
|
||||
To copy content from A to B
|
||||
|
||||
`git checkout B`
|
||||
|
||||
`git merge A`
|
||||
|
||||
If A is test and B is main then
|
||||
|
||||
`git checkout main`
|
||||
|
||||
`git merge test`
|
||||
|
||||
To create a branch of specific commit:
|
||||
|
||||
`git checkout -b old_state <commit_hash>`
|
||||
|
||||
- Configuration
|
||||
|
||||
`git config —-global [user.name](http://user.name) 'moss'`
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
# Managing Different Accounts
|
||||
|
||||
|
||||
|
||||
Using more than 1 git account on same machine
|
||||
|
||||
### While cloning
|
||||
- git clone git@github.com-work
|
||||
Here `git@github.com-work` is ssh id
|
||||
|
||||
|
||||
So if username is a1 and a2 then
|
||||
|
||||
for a1:
|
||||
`git clone git@github.com:a1/code-repo.git`
|
||||
|
||||
for a2:
|
||||
`git clone git@github.com:a2/code-repo.git`
|
||||
|
||||
- To add new origin
|
||||
`git remote add origin git@github.com-work:a2/code-repo.git`
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
# Project commit ids
|
||||
|
||||
fixed scheduling of playlist : `32be0512c184d9d530efce99d1bc29aa4d38ab08`
|
||||
|
||||
latest commit for bull: `7fafc78a68c80629eed471b7590f3a540565478b`
|
||||
|
||||
removed job and using promises: `2c051842e47cfc5424a9e39b61a27671feb5087f`
|
||||
|
||||
latest after download/upload gofile: `b880014f924cd3147d3a0449eba2f1a7e1f8dc8d`
|
||||
|
||||
front end:
|
||||
|
||||
added scheduling: `c310df967e76bb9ca931f59a31fa714102922571`
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
# Setting multiple accounts
|
||||
|
||||
Source: [https://betterprogramming.pub/how-to-use-multiple-github-accounts-with-one-computer-c9ba3f851b75](https://betterprogramming.pub/how-to-use-multiple-github-accounts-with-one-computer-c9ba3f851b75)
|
||||
|
||||
For windows I use
|
||||
|
||||
```
|
||||
ssh-keygen -t rsa -C “your-email-address”
|
||||
```
|
||||
|
||||
- **t** stands for ‘**type**’ and **rsa** is type of encryption
|
||||
- **C** is for comment
|
||||
|
||||
3. The following will then show:
|
||||
|
||||
```
|
||||
Generating public/private rsa key pair.
|
||||
Enter file in which to save the key (/c/Users/your_username/.ssh/id_rsa):
|
||||
```
|
||||
|
||||
Copy and paste the path followed by an **identifiable name** for the file:
|
||||
|
||||
```
|
||||
/c/Users/your_username/.ssh/id_rsa_IDENTIFIABLE_NAME_HERE
|
||||
```
|
||||
|
||||
I named my one test for the sake of this tutorial:
|
||||
|
||||
```
|
||||
/c/Users/your_username/.ssh/id_rsa_test
|
||||
```
|
||||
|
||||
**Make sure you don’t override id_rsa as this is your existing key for your original account.**
|
||||
|
||||
It will then ask you for the following:
|
||||
|
||||
```
|
||||
Enter passphrase (empty for no passphrase):
|
||||
Enter same passphrase again:
|
||||
```
|
||||
|
||||
Press ‘Enter’ twice to leave it blank.
|
||||
|
||||
You can now type in the following command to see all the SSH keys you have on your local machine:
|
||||
|
||||
```
|
||||
ls -al ~/.ssh
|
||||
```
|
||||
|
||||
- **ls** lists all the files in the current directory
|
||||
- **a** is for listing all files including hidden ones
|
||||
- **l** is for listing in a long format
|
||||
|
||||
You should then get something similar to this:
|
||||
|
||||
```
|
||||
total 46
|
||||
drwxr-xr-x 1 your_username 1049089 0 Jan 26 10:40 .
|
||||
drwxr-xr-x 1 your_username 1049089 0 Jan 23 12:12 ..
|
||||
-rw-r--r-- 1 your_username 1049089 3326 Nov 30 11:21 id_rsa
|
||||
-rw-r--r-- 1 your_username 1049089 748 Nov 30 11:21 id_rsa.pub
|
||||
-rw-r--r-- 1 your_username 1049089 1675 Jan 26 10:40 id_rsa_test
|
||||
-rw-r--r-- 1 your_username 1049089 399 Jan 26 10:40 id_rsa_test.pub
|
||||
-rw-r--r-- 1 your_username 1049089 803 Nov 30 12:08 known_hosts
|
||||
```
|
||||
|
||||
You should be able to see your new SSH key file. As you can see in my one I have both **id_rsa_test** and **id_rsa_test.pub**.
|
||||
|
||||
**id_rsa_test** is your private key stored on your machine, whilst **id_rsa_test.pub** is the public key which you will provide GitHub with.
|
||||
|
||||
Next you need to copy the **SSH key** which is stored in **id_rsa_test.pub** file. You can open this in text editor of your choice. I am currently using atom so I opened the file using the following command:
|
||||
|
||||
```
|
||||
atom ~/.ssh/id_rsa_test.pub
|
||||
```
|
||||
|
||||
You will then get something similar to this:
|
||||
|
||||
```
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDEmSbc7ms4SNIf7G0e9EqdrQRTB17VFTqRtCbQ55sSc11xZP5B07UXf9+................a955cf1GUzsNIr60E7VuVxirrr+K2WcleqifnDEg1H/VbyJtEekh4Aav9csBwemTz3test@test.com
|
||||
```
|
||||
|
||||
The key is actually longer but I shortened it for the sake of this tutorial.
|
||||
|
||||
Copy this and navigate to your **GitHub account** → **Settings** → **SSH and GPG keys**
|
||||
|
||||

|
||||
|
||||
Click on **New SSH key**
|
||||
|
||||

|
||||
|
||||
Give your new key a title and then paste the **new generated SSH key** you copied before. ***It is a good idea to name your keys after the machine they’re from. As you can see I have three, Macbook, Windows and Cloud9 IDE***.
|
||||
|
||||
If you’re on a Mac you should be able to add this key on your terminal as well using the command below:
|
||||
|
||||
```
|
||||
ssh-add ~/.ssh/id_rsa_test
|
||||
```
|
||||
|
||||
For enabling ssh:
|
||||
|
||||
39
|
||||
|
||||
In Windows PowerShell (run as admin):
|
||||
|
||||
1. Check the current status of **ssh-agent**:
|
||||
|
||||
`Get-Service | ?{$_.Name -like '*ssh-agent*'} | select -Property Name, StartType, Status`
|
||||
|
||||
2. Enable the Service if it is disabled:
|
||||
|
||||
`Set-Service -Name ssh-agent -StartupType Manual`
|
||||
|
||||
3. Start the Service:
|
||||
|
||||
`Start-Service ssh-agent`
|
||||
|
||||
then
|
||||
|
||||
`cd ~`
|
||||
|
||||
4. Add your key as before:
|
||||
|
||||
`ssh-add <path to the key>`
|
||||
|
||||
|
||||
Creating config file : format
|
||||
|
||||
```
|
||||
Host github.com
|
||||
HostName github.com
|
||||
User git
|
||||
IdentityFile ~/.ssh/id_rsa
|
||||
Host github.com-work
|
||||
HostName github.com
|
||||
User git
|
||||
IdentityFile ~/.ssh/id_rsa_work
|
||||
```
|
||||
|
|
@ -0,0 +1,287 @@
|
|||
# Heroku
|
||||
|
||||
[Installation and Pushing Code](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/Heroku%20531d47e94b8843d7a0dc8ffce482bf9e/Installation%20and%20Pushing%20Code%20d782fb23e4a642358c74.md)
|
||||
|
||||
[Connecting with PostgreSQL Database](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/Heroku%20531d47e94b8843d7a0dc8ffce482bf9e/Connecting%20with%20PostgreSQL%20Database%2027806e96bc2941.md)
|
||||
|
||||
Heroku alternatives:
|
||||
|
||||
[https://www.youtube.com/watch?v=UZsMx_7LEj8](https://www.youtube.com/watch?v=UZsMx_7LEj8)
|
||||
|
||||
[https://www.youtube.com/watch?v=MusIvEKjqsc](https://www.youtube.com/watch?v=MusIvEKjqsc)
|
||||
|
||||
[https://bloggersdesire.com/hosting-trial-no-credit-card/](https://bloggersdesire.com/hosting-trial-no-credit-card/) : site
|
||||
|
||||
[https://www.guru99.com/free-web-hosting-sites.html](https://www.guru99.com/free-web-hosting-sites.html)
|
||||
|
||||
uptimerobot nodejs for bots
|
||||
|
||||
[https://www.staas.io/dashboard/stack?id=nodejsweek3305&cmd=restart&error=&success=Stack RESTART command is processed&data_id=Xf6PbWjQqrEuN3-W5K_tV](https://www.staas.io/dashboard/stack?id=nodejsweek3305&cmd=restart&error=&success=Stack%20RESTART%20command%20is%20processed&data_id=Xf6PbWjQqrEuN3-W5K_tV)
|
||||
|
||||
qovery
|
||||
glitch : for hosting
|
||||
|
||||
surge : for frontend
|
||||
[https://host.ehxz.tk/](https://host.ehxz.tk/)
|
||||
|
||||
replit
|
||||
|
||||
deta cloud: [https://www.deta.sh/](https://www.deta.sh/) nodejs
|
||||
|
||||
adaptable io
|
||||
|
||||
back4app
|
||||
|
||||
coolify : self hosted platform means we need our own server
|
||||
|
||||
for deta cloud server file should be index.js not app.js or server.js and at last of index.js add this:
|
||||
|
||||
`module.exports=app` where `app=express()`
|
||||
|
||||
elephantSQL : for postgreSQL
|
||||
|
||||
[https://supabase.com/pricing](https://supabase.com/pricing) : for postgres
|
||||
|
||||
[https://www.youtube.com/watch?v=prjMJtXCR-g](https://www.youtube.com/watch?v=prjMJtXCR-g) : with database too
|
||||
|
||||
[https://ekomenyong.com/posts/how-to-setup-free-postgresql-database-on-railway-app](https://ekomenyong.com/posts/how-to-setup-free-postgresql-database-on-railway-app)
|
||||
|
||||
[https://blog.railway.app/p/postgre-backup](https://blog.railway.app/p/postgre-backup)
|
||||
|
||||
- Puppeteer on render cloud
|
||||
|
||||
[https://render.com/docs/deploy-puppeteer-node](https://render.com/docs/deploy-puppeteer-node)
|
||||
|
||||
Browser as service : [https://dashboard.phantomjscloud.com/](https://dashboard.phantomjscloud.com/)
|
||||
|
||||
[https://phantomjscloud.com/docs/http-api/#script-examples](https://phantomjscloud.com/docs/http-api/#script-examples)
|
||||
|
||||
video related to it : [https://www.youtube.com/watch?v=lcSMCta1Bcg](https://www.youtube.com/watch?v=lcSMCta1Bcg)
|
||||
|
||||
uploading on vercel : [https://www.youtube.com/watch?v=X6VIWHl3JmM](https://www.youtube.com/watch?v=X6VIWHl3JmM)
|
||||
|
||||
- code for uploading in vercel
|
||||
|
||||
```jsx
|
||||
const btoa = require("btoa");
|
||||
const path = require("path");
|
||||
let chromium;
|
||||
// Check if we are running locally or on Vercel
|
||||
if (!process.env.AWS_LAMBDA_FUNCTION_VERSION) {
|
||||
const puppeteer = require("puppeteer");
|
||||
chromium = {
|
||||
puppeteer,
|
||||
};
|
||||
} else {
|
||||
chromium = require("chrome-aws-lambda");
|
||||
}
|
||||
const renderHTML = require("./render-html");
|
||||
|
||||
/**
|
||||
* Normalizes the theme name by adding a prefix `jsonresume-theme` if not present
|
||||
* @param {String} value Name of the theme
|
||||
* @param {String} defaultValue Default Theme
|
||||
*/
|
||||
const normalizeTheme = (value, defaultValue = "even") => {
|
||||
const theme = value || defaultValue;
|
||||
|
||||
// If theme has a relative path provided, immediately return
|
||||
if (theme[0] === ".") {
|
||||
return theme;
|
||||
}
|
||||
|
||||
return theme.match("jsonresume-theme-.*")
|
||||
? theme
|
||||
: `jsonresume-theme-${theme}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the theme Package
|
||||
* @param {String} theme Normalized theme name
|
||||
*/
|
||||
const getThemePackage = (theme) => {
|
||||
if (theme[0] === ".") {
|
||||
theme = path.join(process.cwd(), theme, "index.js");
|
||||
}
|
||||
|
||||
try {
|
||||
const themePackage = require(theme);
|
||||
return themePackage;
|
||||
} catch (err) {
|
||||
// Theme not installed
|
||||
throw new Error(
|
||||
"You have to install this theme relative to the folder to use it e.g. `npm install " +
|
||||
theme +
|
||||
"`"
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Parses the `resumeJson` to render a pretty HTML
|
||||
* @param {Object} resumeJson Resume data
|
||||
* @param {String} themeName Name of the theme
|
||||
*/
|
||||
const parse = async (resumeJson, themeName) => {
|
||||
const html = await renderHTML({
|
||||
resume: resumeJson,
|
||||
themePath: themeName,
|
||||
});
|
||||
return html;
|
||||
};
|
||||
|
||||
// See https://vercel.com/knowledge/how-to-enable-cors
|
||||
const allowCors = (fn) => async (req, res) => {
|
||||
res.setHeader("Access-Control-Allow-Credentials", true);
|
||||
res.setHeader("Access-Control-Allow-Origin", "*");
|
||||
res.setHeader(
|
||||
"Access-Control-Allow-Methods",
|
||||
"GET,OPTIONS,PATCH,DELETE,POST,PUT"
|
||||
);
|
||||
res.setHeader(
|
||||
"Access-Control-Allow-Headers",
|
||||
"X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version"
|
||||
);
|
||||
|
||||
// Handle CORS pre-flight
|
||||
if (req.method === "OPTIONS") {
|
||||
res.status(200).end();
|
||||
return;
|
||||
}
|
||||
|
||||
return await fn(req, res);
|
||||
};
|
||||
|
||||
const handler = async (req, res) => {
|
||||
try {
|
||||
const { resumeData } = req.body;
|
||||
const normalizedTheme = normalizeTheme(resumeData.meta.theme, "even");
|
||||
const themePackage = getThemePackage(normalizedTheme);
|
||||
const html = await parse(resumeData, normalizedTheme);
|
||||
const browser = await chromium.puppeteer.launch();
|
||||
const page = await browser.newPage();
|
||||
await page.emulateMediaType(
|
||||
(themePackage.pdfRenderOptions &&
|
||||
themePackage.pdfRenderOptions.mediaType) ||
|
||||
"screen"
|
||||
);
|
||||
await page.goto(
|
||||
`data:text/html;base64,${btoa(unescape(encodeURIComponent(html)))}`,
|
||||
{ waitUntil: "networkidle0" }
|
||||
);
|
||||
if (themePackage.pdfViewport) {
|
||||
await page.setViewport(themePackage.pdfViewport);
|
||||
}
|
||||
const pdf = await page.pdf({
|
||||
format: "Letter",
|
||||
printBackground: true,
|
||||
margin: {
|
||||
top: "0.5in",
|
||||
bottom: "0.5in",
|
||||
left: "0.5in",
|
||||
right: "0.5in",
|
||||
},
|
||||
...themePackage.pdfRenderOptions,
|
||||
});
|
||||
|
||||
await browser.close();
|
||||
|
||||
res.setHeader("Content-Type", "application/pdf");
|
||||
res.setHeader("Content-Length", pdf.length);
|
||||
res.send(pdf);
|
||||
} catch (err) {
|
||||
res.status(500);
|
||||
res.json({
|
||||
error: err,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = allowCors(handler);
|
||||
```
|
||||
|
||||
|
||||
- Glitch(to test the app without hosting)
|
||||
|
||||
[https://www.youtube.com/watch?v=3hVf4Giy5nc](https://www.youtube.com/watch?v=3hVf4Giy5nc)
|
||||
|
||||

|
||||
|
||||
- Puppeteer on glitch
|
||||
|
||||

|
||||
|
||||
this should be the version ie 1.3.0 not the latest one
|
||||
|
||||
```jsx
|
||||
const browser = await puppeteer.launch({
|
||||
args: ['--no-sandbox']
|
||||
});
|
||||
```
|
||||
|
||||
- FireBase
|
||||
|
||||
[https://www.youtube.com/watch?v=WaYPrpOvsZE](https://www.youtube.com/watch?v=WaYPrpOvsZE)
|
||||
|
||||
- Guide
|
||||
|
||||
To host a Node.js application in Firebase, you can follow these steps:
|
||||
|
||||
1. Set up Firebase: Visit the Firebase website (**[https://firebase.google.com/](https://firebase.google.com/)**) and create an account if you don't have one already. Once logged in, create a new project.
|
||||
2. Install Firebase CLI: Install the Firebase Command Line Interface (CLI) globally on your machine by running the following command in your terminal:
|
||||
|
||||
```
|
||||
Copy code
|
||||
npm install -g firebase-tools
|
||||
|
||||
```
|
||||
|
||||
3. Initialize Firebase: In your terminal, navigate to your Node.js project's root directory. Run the following command to initialize Firebase within your project:
|
||||
|
||||
```
|
||||
csharpCopy code
|
||||
firebase init
|
||||
|
||||
```
|
||||
|
||||
This will prompt you to select the Firebase features you want to use. Choose "Hosting" and select your Firebase project from the list.
|
||||
|
||||
4. Configure Firebase Hosting: During the initialization process, you'll be asked to configure Firebase Hosting. Set the public directory to the folder containing your Node.js application's static files. If your Node.js app serves static files from a **`public`** folder, you can specify it as the public directory. Firebase Hosting is designed to host static files, so for a Node.js application, you'll need to configure Firebase to serve the static files while handling dynamic requests.
|
||||
5. Modify Firebase Configuration (Optional): If your Node.js application requires additional server-side configuration, you can modify the generated **`firebase.json`** file to include a **`rewrites`** property. This allows you to define rules for routing requests to your Node.js application. For example:
|
||||
|
||||
```
|
||||
jsonCopy code
|
||||
"rewrites": [
|
||||
{
|
||||
"source": "**",
|
||||
"function": "yourNodeJsFunction"
|
||||
}
|
||||
]
|
||||
|
||||
```
|
||||
|
||||
This configuration redirects all requests to your Node.js function. Replace **`"yourNodeJsFunction"`** with the appropriate function name.
|
||||
|
||||
6. Deploy to Firebase Hosting: Once your configuration is complete, deploy your Node.js application to Firebase Hosting by running the following command:
|
||||
|
||||
```
|
||||
Copy code
|
||||
firebase deploy
|
||||
|
||||
```
|
||||
|
||||
This will upload your static files and deploy your Node.js application to Firebase Hosting.
|
||||
|
||||
7. Access Your Deployed Application: After the deployment is successful, Firebase will provide you with a URL where your Node.js application is hosted. You can access it from any web browser.
|
||||
|
||||
Keep in mind that Firebase Hosting is primarily designed for hosting static files, so it might not be suitable for all types of Node.js applications. If your application has specific server-side requirements or requires more complex routing and API functionality, you might need to consider other hosting options like virtual private servers (VPS), cloud platforms, or dedicated Node.js hosting providers.
|
||||
|
||||
Also, ensure that your Node.js application is properly configured to handle production deployments and security considerations such as environment variables and authentication mechanisms.
|
||||
|
||||
for testing locally use `firebase serve`
|
||||
|
||||
|
||||
- Video hosting platform
|
||||
|
||||
1: vimeo
|
||||
2: vidyard
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
# Connecting with PostgreSQL Database
|
||||
|
||||
- Local important commands for exporting and importing
|
||||
|
||||
### Exporting postgresql Database
|
||||
|
||||
We need to create a dump file. Here *smart-brain* is name of database
|
||||
|
||||
`pg_dump -U postgres smart-brain > dump.sql`
|
||||
|
||||
### Importing postgresql Database
|
||||
|
||||
`psql -U postgres smart-brain < dump.sql`
|
||||
|
||||
For using insert into instead of copy: [https://stackoverflow.com/questions/2827072/sql-convert-backup-file-from-copy-format-to-insert-format](https://stackoverflow.com/questions/2827072/sql-convert-backup-file-from-copy-format-to-insert-format)
|
||||
|
||||
`pg_dump --column-inserts -U <dbuser> <database> > dumpWithInserts.sql`
|
||||
|
||||
for railway cloud:
|
||||
|
||||
[https://blog.railway.app/p/postgre-backup](https://blog.railway.app/p/postgre-backup)
|
||||
|
||||
The above may not work well in windows so we can use the pgadmin which is workbench. To create dump file use backup functionality with binary encoding. This dump file can be easily imported using restore functionality.
|
||||
|
||||
Some extra functionality like:
|
||||
|
||||
To get list of tables: `\d`
|
||||
|
||||
to get schema of table ‘users’: `\d users;`
|
||||
|
||||
|
||||
### Importing dump file to heroku created by pgadmin
|
||||
|
||||
dump file to be imported to heroku must be publically accessible http url. Dropbox is recommended and remove letter ‘s’ from https(https→ http).
|
||||
|
||||
`heroku pg: backups: restore ‘http://…..’`
|
||||
|
||||
- Configuration for postgreSQL in nodejs for production mode:
|
||||
|
||||
```jsx
|
||||
const knex = require("knex")({
|
||||
client: "pg",
|
||||
connection: {
|
||||
// host: "127.0.0.1",
|
||||
connectionString: process.env.DATABASE_URL,
|
||||
ssl: { rejectUnauthorized: false },
|
||||
|
||||
|
||||
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
This database_url is to be uploaded in heroku config file section under settings when navigated to the particular app.Refer to the image:
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
This database_url can be accessed by using the heroku command:
|
||||
|
||||
heroku pg:info
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
This add-on property contains databse url.
|
||||
|
||||
|
||||
### Accessing database through command prompt:
|
||||
|
||||
`heroku pg:psql -a face-extractor-app`
|
||||
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
# Installation and Pushing Code
|
||||
|
||||
## I**nstallation**
|
||||
|
||||
- At root directory of nodejs app
|
||||
|
||||
```bash
|
||||
git init
|
||||
git add .
|
||||
git commit -m 'initialize'
|
||||
```
|
||||
|
||||
|
||||
• (Make sure to install heroku cli)
|
||||
|
||||
`• heroku create or heroku create appname`
|
||||
|
||||
- If there is already an existing app then we need to change the prev origin to current one by:
|
||||
|
||||
`heroku git:remote -a appname`
|
||||
|
||||
- For changing app name, remote name has to be changed too.
|
||||
|
||||
```bash
|
||||
git remote rename heroku newname
|
||||
```
|
||||
|
||||
|
||||
|
||||
or
|
||||
|
||||
```bash
|
||||
git remote heroku newname
|
||||
heroku git:remote -a newname
|
||||
```
|
||||
|
||||
- For changing app name(this has to be done before)
|
||||
|
||||
`heroku apps: rename newname`
|
||||
|
||||
or for outside git repository
|
||||
|
||||
`heroku apps: rename newname —app oldname`
|
||||
|
||||
## **Pushing Code**
|
||||
|
||||
`git push heroku main`
|
||||
|
||||
For non-main branch:
|
||||
|
||||
`git push heroku testbranch:main`
|
||||
|
||||
**In nodejs app:**
|
||||
|
||||
```jsx
|
||||
app.listen(process.env.PORT || 3000,()=>{
|
||||
console.log('listening');
|
||||
})
|
||||
```
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
# Javascript
|
||||
|
||||
- **Split regex**
|
||||
|
||||
1: when using split function using regex, if we want to include delimiters in array instead of just skipping them then we need to include brackets for delimiters.
|
||||
for eg:
|
||||
|
||||
```jsx
|
||||
calcInput='2*3'
|
||||
let arr = calcInput.split(/([*\/+-])/);
|
||||
// arr-> ['2', '*', '3']
|
||||
without brackets split(/[*\/+-])/)
|
||||
// arr=['2', '3']
|
||||
```
|
||||
|
||||
|
||||
2: **typeof**: to get type of literal.
|
||||
|
||||
for eg:
|
||||
|
||||
`typeof 'str’` -> ‘string’
|
||||
|
||||
- regex reference
|
||||
|
||||
[JavaScript RegExp Reference](https://www.w3schools.com/jsref/jsref_obj_regexp.asp)
|
||||
|
||||
```python
|
||||
import re
|
||||
In [14]: par = "This is a paragraph? So it is! Ok, there are 3 sentences."
|
||||
In [15]: re.split(r'[.!?]+', par)
|
||||
Out[15]: ['This is a paragraph', ' So it is', ' Ok, there are 3 sentences', '']
|
||||
```
|
||||
|
||||
for splitting sentences in python
|
||||
|
||||
- Parsing using regex
|
||||
|
||||
Suppose if we wnna extract id from url or text then
|
||||
|
||||
`id = /var k__id = "(.*?)"/.exec(result)[1]`
|
||||
|
||||
also to extract id from embed youtube video.
|
||||
|
||||
for eg:
|
||||
|
||||
```jsx
|
||||
let url="[https://www.youtube.com/embed/Ko58_KjgM0E](https://www.youtube.com/embed/Ko58_KjgM0E)"
|
||||
let reg=/embed\/(.*)/
|
||||
const id=reg.exec('https://www.youtube.com/embed/Ko58_KjgM0E')[1]
|
||||
|
||||
// Output:
|
||||
// "Ko58_KjgM0E"
|
||||
```
|
||||
|
||||
- Using fetch to send form data
|
||||
|
||||
in body use format `<key>=<value>` and use `content-type: "application/x-www-form-urlencoded"`.
|
||||
|
||||
```jsx
|
||||
const getToken = async () => {
|
||||
const url = "https://accounts.spotify.com/api/token";
|
||||
const authOptions = {
|
||||
method: "post",
|
||||
// url: "https://accounts.spotify.com/api/token",
|
||||
headers: {
|
||||
Authorization:
|
||||
"Basic " +
|
||||
new Buffer(clientID + ":" + clientSecret).toString("base64"),
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
// form data with key 'grant_type' and value 'client_credentials'
|
||||
// written as
|
||||
body: "grant_type=client_credentials",
|
||||
|
||||
// json: true,
|
||||
};
|
||||
|
||||
const result = await fetch(url, authOptions);
|
||||
const data = await result.json();
|
||||
return data.access_token;
|
||||
};
|
||||
```
|
||||
|
||||
- HTTP basics
|
||||
|
||||
[https://eloquentjavascript.net/18_http.html](https://eloquentjavascript.net/18_http.html#HTTP%201.1)
|
||||
|
||||
- onchange on select element
|
||||
|
||||
Another approach which can be handy in some situations, is passing the value of the selected `<option />` directly to the function like this:
|
||||
|
||||
```jsx
|
||||
function myFunction(chosen) {
|
||||
console.log(chosen);
|
||||
}
|
||||
|
||||
<select onChange="myFunction(this.options[this.selectedIndex].value)">
|
||||
<option value="1">Text 1</option>
|
||||
<option value="2">Text 2</option>
|
||||
</select>
|
||||
```
|
||||
- for react
|
||||
```jsx
|
||||
<select
|
||||
onChange={(e) =>
|
||||
myFunction(e.target.options[e.target.selectedIndex].value)
|
||||
}
|
||||
```
|
||||
- Stimulate ctrl+click event
|
||||
|
||||
[https://stackoverflow.com/questions/34255506/simulate-ctrl-click-with-javascript-or-jquery-to-open-a-new-tab-without-focus](https://stackoverflow.com/questions/34255506/simulate-ctrl-click-with-javascript-or-jquery-to-open-a-new-tab-without-focus)
|
||||
|
||||
In pure javascript, you can use the `[MouseEvent](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/MouseEvent)` for that:
|
||||
|
||||
```jsx
|
||||
document.getElementById("todo").dispatchEvent(new MouseEvent("click", {ctrlKey: true}));
|
||||
|
||||
```
|
||||
|
||||
To programatically open a new tab you can do that:
|
||||
|
||||
```jsx
|
||||
const a = document.createElement("a");
|
||||
a.setAttribute("href", "https://www.google.com/");
|
||||
a.dispatchEvent(new MouseEvent("click", {ctrlKey: true}));
|
||||
```
|
||||
|
||||
- Local storage
|
||||
|
||||
```jsx
|
||||
const notestring = localStorage.getItem("notes");
|
||||
|
||||
// we can store objects so we need to convert them in json string first
|
||||
const arrString = JSON.stringify(notes);
|
||||
localStorage.setItem("notes", arrString);
|
||||
// here 'notes' is key and arrString is value
|
||||
|
||||
// to remove the key
|
||||
localStorage.removeItem("notes");
|
||||
```
|
||||
|
||||
- Use npm package in vanilla js
|
||||
|
||||
install browserify using
|
||||
|
||||
`npm install -g browserify`
|
||||
|
||||
then install npm package in same directory
|
||||
|
||||
`npm i js-crypto-rsa`
|
||||
|
||||
script.js
|
||||
|
||||
```jsx
|
||||
const rsa=require('js-crypto-rsa')
|
||||
|
||||
const key=rsa.generateKey(2048)
|
||||
|
||||
```
|
||||
|
||||
finally use
|
||||
|
||||
`browserify script.js -o bundle.js`
|
||||
|
||||
in index.html
|
||||
|
||||
`<script src="bundle.js"></script>`
|
||||
|
|
@ -0,0 +1,983 @@
|
|||
# Linux
|
||||
|
||||
- File structure
|
||||
|
||||
bin: executables
|
||||
|
||||
sbin: system binaries and require root
|
||||
|
||||
lib: bin and sbin store common libraries
|
||||
|
||||
usr → bin: non essential installed binaries
|
||||
|
||||
usr → local → bin : locally compiled, its separate to stop conflict when installed from apt,snap,etc.
|
||||
|
||||
etc(editable text configuration): contains config files, executables for booting and log files
|
||||
|
||||
home: contains data of all users
|
||||
|
||||
boot: for booting linux kernel
|
||||
|
||||
- GUI Resource Manager
|
||||
|
||||
Stacer
|
||||
|
||||
[stacer_1.1.0+ds-1_amd64.deb](../../_resources/stacer_1.1.0ds-1_amd64.deb)
|
||||
|
||||
[bleachbit_4.4.2-1_all.deb](../../_resources/bleachbit_4.4.2-1_all.deb)
|
||||
|
||||
- Uninstalling
|
||||
|
||||
```bash
|
||||
sudo apt-get remove heroku-toolbelt
|
||||
```
|
||||
|
||||
When you remove a package in Ubuntu, the packaged data is removed, but it may leave small, modified user configuration files. This is intentional because if you install the same program again, it would use those configuration files.
|
||||
|
||||
If you want to remove it completely, you can use apt purge command. You can use it instead of apt remove command or after running the apt remove command.
|
||||
|
||||
```
|
||||
sudo apt purge program_name
|
||||
```
|
||||
|
||||
command that cleans up leftover package traces like dependencies that are no longer used, old Linux kernel headers that won’t be used anymore.
|
||||
|
||||
In the terminal, just run this command:
|
||||
|
||||
```
|
||||
sudo apt autoremove
|
||||
```
|
||||
|
||||
To get a list of dependency:(For debian only)
|
||||
|
||||
`dpkg -l | grep 'geany' | awk '{print $2}' | tr "\n" " “`
|
||||
|
||||
- Handwritten
|
||||
|
||||
[linux.pdf](../../_resources/linux.pdf)
|
||||
|
||||
[linux.pdf](../../_resources/linux%201.pdf)
|
||||
|
||||
- Basics
|
||||
|
||||
|
||||
- Aliases
|
||||
|
||||
```bash
|
||||
myFold="~/Files/Scripts/Main"
|
||||
cd $myFold
|
||||
```
|
||||
|
||||
for permanent
|
||||
|
||||
[https://phoenixnap.com/kb/linux-set-environment-variable](https://phoenixnap.com/kb/linux-set-environment-variable)
|
||||
|
||||
# **Set an Environment Variable in Linux Permanently**
|
||||
|
||||
If you wish a variable to persist after you close the shell session, you need to set it as an environmental variable permanently. You can choose between setting it for the current user or all users.
|
||||
|
||||
1. To set permanent environment variables for a single user, [edit the .bashrc file](https://phoenixnap.com/kb/bashrc):
|
||||
|
||||
```
|
||||
sudo nano ~/.bashrc
|
||||
```
|
||||
|
||||
2. Write a line for each variable you wish to add using the following syntax:
|
||||
|
||||
```
|
||||
export [VARIABLE_NAME]=[variable_value]
|
||||
```
|
||||
|
||||

|
||||
|
||||
3. Save and exit the file. The changes are applied after you restart the shell. If you want to apply the changes during the current session, use the [source command](https://phoenixnap.com/kb/linux-source-command):
|
||||
|
||||
```
|
||||
source ~/.bashrc
|
||||
```
|
||||
|
||||
4. To set permanent environment variables for all users, create an **`.sh`** file in the **`/etc/profile.d`** folder:
|
||||
|
||||
```
|
||||
sudo nano /etc/profile.d/[filename].sh
|
||||
```
|
||||
|
||||
5. The syntax to add variables to the file is the same as with **`.bashrc`**:
|
||||
|
||||

|
||||
|
||||
6. Save and exit the file. The changes are applied at the next logging in.
|
||||
|
||||
Alias commands
|
||||
|
||||
|
||||
which command: to get path of certain app:
|
||||
|
||||
```
|
||||
$ which heroku
|
||||
/snap/bin/heroku
|
||||
```
|
||||
|
||||
Completey remove folder with contents:
|
||||
|
||||
`sudo rm -r heroku`
|
||||
|
||||
for chamging names
|
||||
|
||||
`for file in [y2mate.com](http://y2mate.com/)*; do
|
||||
mv "$file" "${file/y2mate.com -/}"
|
||||
done`
|
||||
|
||||
- chagpt example
|
||||
|
||||
If you want to rename files that start with **`[SPOTIFY-DOWNLOADER.COM]`** and remove that part, you can use a similar **`rename`** command with a regular expression. Here's how you can do it:
|
||||
|
||||
```bash
|
||||
bashCopy code
|
||||
rename 's/^\[SPOTIFY-DOWNLOADER\.COM\]//' '[SPOTIFY-DOWNLOADER.COM]'*
|
||||
|
||||
```
|
||||
|
||||
This command will search for files that start with **`[SPOTIFY-DOWNLOADER.COM]`** and replace that part with an empty string, effectively removing it from the filenames. Make sure to use single quotes around the pattern **`[SPOTIFY-DOWNLOADER.COM]*`** to prevent shell expansion of the square brackets.
|
||||
|
||||
As always, it's a good idea to test this command on a small set of files or create backups before applying it to your entire file set.
|
||||
|
||||
|
||||
- Installing
|
||||
|
||||
Step 1. Before running the tutorial below, it’s important to make sure your system is up to date by running the following `apt` commands in the terminal:
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install software-properties-common apt-transport-https wget ca-certificates gnupg2
|
||||
```
|
||||
|
||||
Step 2. Installing VSCodium on Linux Mint 21.
|
||||
|
||||
By default, VSCodium is not available on the Linux Mint 21 base repository. Now we add the VSCodium repository to your system using the following command:
|
||||
|
||||
```bash
|
||||
echo deb [signed-by=/usr/share/keyrings/vscodium.gpg] https://download.vscodium.com/debs vscodium main | sudo tee /etc/apt/sources.list.d/vscodium.list
|
||||
```
|
||||
|
||||
Next, import the GPG key:
|
||||
|
||||
```bash
|
||||
sudo wget -O- https://gitlab.com/paulcarroty/vscodium-deb-rpm-repo/raw/master/pub.gpg | gpg --dearmor | sudo tee /usr/share/keyrings/vscodium.gpg
|
||||
```
|
||||
|
||||
Now start by updating the packages list and install VSCodium stable by using the command below:
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install codium
|
||||
```
|
||||
|
||||
- Important tools and softwares
|
||||
|
||||
`sudo apt install glances` : better task manager
|
||||
|
||||

|
||||
|
||||
it is extension of task manager
|
||||
|
||||
- Taskbar groupping icon
|
||||
|
||||
1. Hold down Control and click on one of the tabs. This will open up the menu for `Window Buttons` (aka Tasklist).
|
||||
2. Click on `Properties`.
|
||||
3. Select "Never" from the `Window grouping` option (in the **Behaviour** section of the dialog)
|
||||
4. Make a note of how to do this because you'll probably want to re-enable grouping if you ever run an app (e.g. a web browser) with dozens of windows open.
|
||||
|
||||
- Get access to priviledged section
|
||||
|
||||
`sudo chmod 755 /usr/local/bin`/codejava
|
||||
|
||||
- Virtual box
|
||||
|
||||
For resizing fix: [https://www.youtube.com/watch?v=yrasRjq3HXw](https://www.youtube.com/watch?v=yrasRjq3HXw)
|
||||
|
||||
- Fun fact
|
||||
|
||||
When typing vi google will say:
|
||||
Did you mean : emacs
|
||||
|
||||
and When typing emacs google will say:
|
||||
|
||||
Did you mean : vi
|
||||
|
||||
- VPN in linux
|
||||
|
||||
[https://atlasvpn.com/vpn-for-linux](https://atlasvpn.com/vpn-for-linux)
|
||||
|
||||
- Linux in mobile
|
||||
|
||||
[https://wiki.termux.com/wiki/Termux-setup-storage](https://wiki.termux.com/wiki/Termux-setup-storage)
|
||||
|
||||
In order to have access to shared storage (/sdcard or /storage/emulated/0), Termux needs a storage access permission. It is not granted by default and is not requested on application startup since it is not necessary for normal application functioning.
|
||||
|
||||
Execute command `termux-setup-storage`
|
||||
|
||||
- Commands
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
- Installing xdm
|
||||
|
||||
[https://www.youtube.com/watch?v=cdMiAgQe3_I](https://www.youtube.com/watch?v=cdMiAgQe3_I)
|
||||
|
||||
|
||||
[xdm-browser-monitor-master.zip](../../_resources/xdm-browser-monitor-master-1.zip)
|
||||
|
||||
- here is the solutions
|
||||
|
||||
download https://github.com/subhra74/xdm-browser-monitor as a zip and extract it
|
||||
|
||||
then go to the chrome extension page and activate developper mode
|
||||
|
||||
then click load extension on the top left and select the chrome folder inside the extracted zip
|
||||
|
||||
after that just clear the error if there is and you are done
|
||||
|
||||
|
||||
|
||||
- Terminal scrolling
|
||||
|
||||
You can temporarily ***prevent scrolling*** by hitting CTRL-S on the keyboard, which will pause output until you hit CTRL-Q.
|
||||
|
||||
- Rhythmbox
|
||||
- **[Board index](https://forums.linuxmint.com/index.php?sid=69cc8b37f90128fea74650ce5fe17d4b)[Main Edition Support](https://forums.linuxmint.com/viewforum.php?f=126&sid=69cc8b37f90128fea74650ce5fe17d4b)[Hardware Support](https://forums.linuxmint.com/viewforum.php?f=49&sid=69cc8b37f90128fea74650ce5fe17d4b)[Sound](https://forums.linuxmint.com/viewforum.php?f=48&sid=69cc8b37f90128fea74650ce5fe17d4b)**
|
||||
|
||||
## [[solved] Rhythmbox: multiple library locations does not work](https://forums.linuxmint.com/viewtopic.php?t=14218&sid=69cc8b37f90128fea74650ce5fe17d4b)
|
||||
|
||||
**Forum rules**Before you post please read [how to get help](https://forums.linuxmint.com/viewtopic.php?f=17&t=83444). Topics in this forum are automatically closed 6 months after creation.
|
||||
|
||||
**[Locked](https://forums.linuxmint.com/posting.php?mode=reply&t=14218&sid=69cc8b37f90128fea74650ce5fe17d4b)**
|
||||
|
||||
**Search[Advanced search](https://forums.linuxmint.com/search.php?sid=69cc8b37f90128fea74650ce5fe17d4b)**
|
||||
|
||||
2 posts • Page **1** of **1**
|
||||
|
||||
**[hans123](https://forums.linuxmint.com/memberlist.php?mode=viewprofile&u=2232&sid=69cc8b37f90128fea74650ce5fe17d4b)**Level 3Posts: [147](https://forums.linuxmint.com/search.php?author_id=2232&sr=posts&sid=69cc8b37f90128fea74650ce5fe17d4b)Joined: Mon Jun 11, 2007 11:15 am
|
||||
|
||||

|
||||
|
||||
### **[[solved] Rhythmbox: multiple library locations does not work](https://forums.linuxmint.com/viewtopic.php?p=87971&sid=69cc8b37f90128fea74650ce5fe17d4b#p87971)**
|
||||
|
||||
[Post](https://forums.linuxmint.com/viewtopic.php?p=87971&sid=69cc8b37f90128fea74650ce5fe17d4b#p87971) by **[hans123](https://forums.linuxmint.com/memberlist.php?mode=viewprofile&u=2232&sid=69cc8b37f90128fea74650ce5fe17d4b)** » June 28, 2008 6:01 PM
|
||||
|
||||
I am trying to add multiple directories where my audio files are located to Rhythmbox. This can only be done with gconf-editor by adding directory URIs to the value /apps/rhythmbox/library_locations.But somehow this does not work for me: The list "library_locations" contains '/media/sda10/music,/media/sda8/My Music' but these directories are not monitored or added in Rhythmbox itself. The directory notation I used is the same that Rhythmbox shows when selecting a Library Location in the preferences (with Browse).What am I doing wrong?
|
||||
|
||||
Last edited by **[LockBot](https://forums.linuxmint.com/memberlist.php?mode=viewprofile&u=338753&sid=69cc8b37f90128fea74650ce5fe17d4b)** on Wed Dec 28, 2022 7:16 am, edited 2 times in total.**Reason:** *Topic automatically closed 6 months after creation. New replies are no longer allowed.*
|
||||
|
||||
[Top](https://forums.linuxmint.com/viewtopic.php?t=14218#top)
|
||||
|
||||
**[hans123](https://forums.linuxmint.com/memberlist.php?mode=viewprofile&u=2232&sid=69cc8b37f90128fea74650ce5fe17d4b)**Level 3Posts: [147](https://forums.linuxmint.com/search.php?author_id=2232&sr=posts&sid=69cc8b37f90128fea74650ce5fe17d4b)Joined: Mon Jun 11, 2007 11:15 am
|
||||
|
||||

|
||||
|
||||
### **[Re: Rhythmbox: multiple library locations does not work](https://forums.linuxmint.com/viewtopic.php?p=88261&sid=69cc8b37f90128fea74650ce5fe17d4b#p88261)**
|
||||
|
||||
[Post](https://forums.linuxmint.com/viewtopic.php?p=88261&sid=69cc8b37f90128fea74650ce5fe17d4b#p88261) by **[hans123](https://forums.linuxmint.com/memberlist.php?mode=viewprofile&u=2232&sid=69cc8b37f90128fea74650ce5fe17d4b)** » June 30, 2008 3:03 AM
|
||||
|
||||
I do not know what you did wrong, but here is a workaround: Point to one directory in Rhythmbox / Pref's / Music / Library Locations. Create Sym Links to the other directories where you keep your music in that one directory and you are set. (So, do not use GConf-Editor) Good Luck!
|
||||
|
||||
[Top](https://forums.linuxmint.com/viewtopic.php?t=14218#top)
|
||||
|
||||
**[Locked](https://forums.linuxmint.com/posting.php?mode=reply&t=14218&sid=69cc8b37f90128fea74650ce5fe17d4b)**
|
||||
|
||||
- Audio equalizer
|
||||
|
||||
[https://linuxhint.com/install-pulseaudio-equalizer-linux-mint/](https://linuxhint.com/install-pulseaudio-equalizer-linux-mint/)
|
||||
|
||||
to start, type `qpaeq` in terminal
|
||||
|
||||
|
||||
- For clearing ram cache
|
||||
|
||||
To clear the RAM cache in Linux, you can use the following methods:
|
||||
|
||||
1. Clear PageCache:
|
||||
|
||||
```
|
||||
shellCopy code
|
||||
$ sudo sync && echo 1 | sudo tee /proc/sys/vm/drop_caches
|
||||
|
||||
```
|
||||
|
||||
2. Clear dentries and inodes:
|
||||
|
||||
```
|
||||
shellCopy code
|
||||
$ sudo sync && echo 2 | sudo tee /proc/sys/vm/drop_caches
|
||||
|
||||
```
|
||||
|
||||
3. Clear PageCache, dentries, and inodes:
|
||||
|
||||
```
|
||||
shellCopy code
|
||||
$ sudo sync && echo 3 | sudo tee /proc/sys/vm/drop_caches
|
||||
|
||||
```
|
||||
|
||||
- Notion app
|
||||
|
||||
[https://filelu.com/azswmk187wnl](https://filelu.com/azswmk187wnl)
|
||||
|
||||
- Adding executable on start menu
|
||||
|
||||
**20**
|
||||
|
||||
If you have a launcher in your desktop, then copy/move the launcher from your desktop to the `~/.local/share/applications/` directory. It should appear in the menu.
|
||||
|
||||
Otherwise, you may manually create a simple `.desktop` launcher (say `eclipse.desktop`) in your `~/.local/share/applications/` directory. The content of the `eclipse.desktop` may be as follows.
|
||||
|
||||
```
|
||||
[Desktop Entry]
|
||||
Name=Eclipse
|
||||
Exec=/full/path/to/the/executable
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Icon=/full/path/to/the/icon-file
|
||||
```
|
||||
|
||||
- Autocomplete
|
||||
|
||||
Using autocomplete is as simple as **pressing the [TAB] and the active command line options will fill in**
|
||||
|
||||
|
||||
- Making custom command
|
||||
|
||||
To create a bash script, enter the following code:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
#on displays the actual folder name
|
||||
echo "the folder is 'pwd'"
|
||||
#then the rest of the files
|
||||
echo "The folder which contains files are 'ls'"
|
||||
```
|
||||
|
||||
Save this file by pressing **CTRL + O** with Nano. Give it the name of your command.
|
||||
|
||||
## **How to make the command executable?**
|
||||
|
||||
If you try to type the name of your bash script, you will notice that it will be executed (run).
|
||||
|
||||
Now, you have to modify the **CHMOD** of the script that you will run by typing:
|
||||
|
||||
```bash
|
||||
chmod +x yourScript
|
||||
```
|
||||
|
||||
Now, copy your script in the path, **/usr/bin**, like below:
|
||||
|
||||
```bash
|
||||
cp yourscript /usr/bin/
|
||||
```
|
||||
|
||||
- Network issues
|
||||
|
||||
When using proton vpn, it can have some effect on dns so using these we can fix problem.
|
||||
|
||||
`nmcli connection show —active`
|
||||
|
||||
output:
|
||||
|
||||
<router_company> … … …
|
||||
|
||||
pvpn-ipv6…. … … …
|
||||
|
||||
`sudo nmcli connection delete pvpn-ipv6…` and
|
||||
|
||||
`sudo nmcli connection delete pvpn-killswitch`(if such there)
|
||||
|
||||
There is another one which is convinent which is change to google dns ie 8.8.8.8
|
||||
|
||||
sudo tee /etc/resolv.conf <<< “nameserver 8.8.8.8”
|
||||
|
||||
and then restart server by
|
||||
|
||||
`sudo service NetworkManager restart` : for ubuntu
|
||||
|
||||
Note: original resolv.conf for linux mint:
|
||||
|
||||
```
|
||||
nameserver 127.0.0.53
|
||||
options edns0 trust-ad
|
||||
```
|
||||
|
||||
- Docker
|
||||
|
||||
[https://docs.docker.com/engine/install/ubuntu/#set-up-the-repository](https://docs.docker.com/engine/install/ubuntu/#set-up-the-repository) : documentation
|
||||
|
||||
[https://www.youtube.com/watch?v=Y4ut8kKpPUs](https://www.youtube.com/watch?v=Y4ut8kKpPUs) : video guide
|
||||
|
||||
```
|
||||
sudo apt-get update
|
||||
$ sudo apt-get install ca-certificates curl gnupg lsb-release
|
||||
(these 4 packages are essential, if already installed then ignore this line)
|
||||
```
|
||||
|
||||
`sudo mkdir -p /etc/apt/keyrings`
|
||||
|
||||
-p flag to create directories if not already created
|
||||
|
||||
`curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg`
|
||||
|
||||
```
|
||||
echo \
|
||||
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
|
||||
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
|
||||
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
```
|
||||
|
||||
Now go to folder /etc/apt/sources.list.d and open file named ‘docker.list’. The contents are:
|
||||
`deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] [https://download.docker.com/linux/ubuntu](https://download.docker.com/linux/ubuntu) vera stable`
|
||||
|
||||
Change **vera** to **jammy** if using linux mint
|
||||
|
||||
`sudo apt-get update`
|
||||
|
||||
for installing docker engine
|
||||
|
||||
`sudo apt-get install docker-ce docker-ce-cli [containerd.io](http://containerd.io/) docker-buildx-plugin docker-compose-plugin`
|
||||
|
||||
- Offline installation
|
||||
|
||||
To download setup(.deb package instead of directly installing it in order to store them for future installation
|
||||
|
||||
1. Use **`apt-get download`** to download the desired software and its dependencies. For example, for the package
|
||||
2. `sudo apt-get download package-name`
|
||||
This command will download the .deb packages (or other package format used by your distribution) to the current directory.
|
||||
3. Copying packages to the target machine (without internet access):
|
||||
- Transfer the downloaded package files (with .deb extension) to the target machine using a USB drive, network sharing, or any other method you prefer.
|
||||
4. Installing packages on the target machine:
|
||||
- Use **`apt`** to install the downloaded packages. Navigate to the directory containing the .deb packages and run:
|
||||
|
||||
```bash
|
||||
|
||||
sudo apt install ./package-name.deb
|
||||
|
||||
```
|
||||
|
||||
**Note**: Before this you need to give _apt permission to download it somewhere else like home or root. Its optional and is to avoid warning
|
||||
|
||||
```
|
||||
sudo chown -Rv _apt:root /var/cache/apt/archives/partial/
|
||||
sudo chmod -Rv 700 /var/cache/apt/archives/partial/
|
||||
```
|
||||
|
||||
- For automatic keypressing
|
||||
|
||||
|
||||
Download xdotool
|
||||
|
||||
[http://apt.ubuntu.com/p/xdotool](http://apt.ubuntu.com/p/xdotool) or
|
||||
|
||||
`apt-get install xdotool`
|
||||
|
||||
- xbinding
|
||||
1. **Install `xbindkeys` and `xdotool` if not already installed:**
|
||||
|
||||
```bash
|
||||
bashCopy code
|
||||
sudo apt-get install xbindkeys xdotool
|
||||
|
||||
```
|
||||
|
||||
2. **Create the kill switch script:**
|
||||
|
||||
Create a script named **`kill_script.sh`** with the following content:
|
||||
|
||||
```bash
|
||||
bashCopy code
|
||||
#!/bin/bash
|
||||
# Kill the running script using pkill
|
||||
pkill -f mouse_click_script.sh # Replace with your script name
|
||||
|
||||
```
|
||||
|
||||
Make it executable with: **`chmod +x kill_script.sh`**
|
||||
|
||||
3. **Create or edit the `~/.xbindkeysrc` configuration file:**
|
||||
|
||||
If you don't have a **`~/.xbindkeysrc`** file, create one. If you do, open it for editing.
|
||||
|
||||
Add the following line to bind a key combination to the kill script:
|
||||
|
||||
```bash
|
||||
bashCopy code
|
||||
"bash /path/to/kill_script.sh"
|
||||
Control+Shift+Delete # Customize the key combination as desired
|
||||
|
||||
```
|
||||
|
||||
Make sure to replace **`/path/to/kill_script.sh`** with the actual path to your kill script and customize the key combination.
|
||||
|
||||
4. **Restart `xbindkeys` to apply changes:**
|
||||
|
||||
Restart the **`xbindkeys`** service to apply your changes:
|
||||
|
||||
```bash
|
||||
bashCopy code
|
||||
killall xbindkeys
|
||||
xbindkeys
|
||||
|
||||
```
|
||||
|
||||
|
||||
To press a key (in this example 'a') every two seconds you can use a script like this :
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
while true; do
|
||||
xdotool key a
|
||||
sleep 2
|
||||
done
|
||||
```
|
||||
|
||||
- Keycodes list
|
||||
|
||||
Up
|
||||
Down
|
||||
Left
|
||||
Right
|
||||
F1
|
||||
F2
|
||||
F3
|
||||
F4
|
||||
F5
|
||||
F6
|
||||
F7
|
||||
F8
|
||||
F9
|
||||
F10
|
||||
F11
|
||||
F12
|
||||
Escape
|
||||
Return
|
||||
Enter
|
||||
Tab
|
||||
BackSpace
|
||||
Delete
|
||||
Insert
|
||||
Home
|
||||
End
|
||||
Page_Up
|
||||
Page_Down
|
||||
Pause
|
||||
Print
|
||||
Scroll_Lock
|
||||
Num_Lock
|
||||
Caps_Lock
|
||||
Shift_L
|
||||
Shift_R
|
||||
Control_L
|
||||
Control_R
|
||||
Meta_L
|
||||
Meta_R
|
||||
Alt_L
|
||||
Alt_R
|
||||
Super_L
|
||||
Super_R
|
||||
Hyper_L
|
||||
Hyper_R
|
||||
|
||||
|
||||
- Wine
|
||||
|
||||
[https://phoenixnap.com/kb/how-to-install-wine-on-ubuntu](https://phoenixnap.com/kb/how-to-install-wine-on-ubuntu)
|
||||
|
||||
for installing gecko
|
||||
|
||||
`wget [https://dl.winehq.org/wine/wine-gecko/2.47.1/wine-gecko-2.47.1-x86_64.msi](https://dl.winehq.org/wine/wine-gecko/2.47.1/wine-gecko-2.47.1-x86_64.msi)`
|
||||
|
||||
`mv wine-gecko-2.47.1-x86_64.msi ~/.wine/drive_c/windows/system32/gecko/`
|
||||
|
||||
`wineboot` when using for first time
|
||||
|
||||
to open uninstaller use
|
||||
|
||||
`wine uninstaller`
|
||||
|
||||
`wine regedit` --for opening regedit
|
||||
|
||||
to install or open files use
|
||||
|
||||
`wine start idman.exe` .
|
||||
|
||||
`remove wine and wineboot` to bring back to its default state and uninstalling all programs
|
||||
|
||||
- Blank browser pages in chromium browsers
|
||||
|
||||
[https://www.ghacks.net/2023/07/12/chromium-based-browsers-are-not-loading-pages-properly-on-linux-heres-how-to-fix-it/](https://www.ghacks.net/2023/07/12/chromium-based-browsers-are-not-loading-pages-properly-on-linux-heres-how-to-fix-it/)
|
||||
|
||||
- Free up space
|
||||
|
||||
[https://www.youtube.com/watch?v=7URA1MnuEi8](https://www.youtube.com/watch?v=7URA1MnuEi8)
|
||||
|
||||
[https://www.tecmint.com/free-disk-space-ubuntu-linux-mint/](https://www.tecmint.com/free-disk-space-ubuntu-linux-mint/)
|
||||
|
||||
- Free swap space
|
||||
|
||||
However, if you really feel that you need to force it, (I can see a scenario where you would want to know the system will be responsive later) you can momentarily disable and re-enable swap
|
||||
|
||||
```
|
||||
sudo swapoff -a
|
||||
sudo swapon -a
|
||||
|
||||
```
|
||||
|
||||
OR alternatively as a single line
|
||||
|
||||
```
|
||||
sudo swapoff -a; sudo swapon -a
|
||||
|
||||
```
|
||||
|
||||
|
||||
- Installing of programs in another drive
|
||||
|
||||
|
||||
[https://forums.linuxmint.com/viewtopic.php?t=361746](https://forums.linuxmint.com/viewtopic.php?t=361746)
|
||||
|
||||
```
|
||||
When you say "It automatically tries to install things to the ssd" - - is there a particular location to which these "things" are installing, or is it all over in different locations? I'm going to assume that it's not all in 1 location, and these installations land wherever is appropriate based on the particular installer. (Otherwise, you would have chosen the target location to install - right?)
|
||||
|
||||
Depending on how much money & effort you want to spend, I can suggest 4 options:
|
||||
|
||||
1. Replace your 15GB SSD with something larger, and then clone the 15GB onto that larger drive.
|
||||
This would be the easiest, assuming that you can make that swap. 15GB is nothing these days, and I'm honestly surprised that you were even able to get Mint to install on something that small. A 256GB can be had for around $50 or less these days, which would give you far more breathing room.
|
||||
|
||||
2. Resize & Repartition your 2TB drive and clone your 15GB into that space. This would be the cheapest option, if you could eke out a 256GB partition from your 2TB as a boot partition. It could be tricky, and I would highly recommend backing up anything important on that drive in case something gets mucked up during the operation...but if done right, you would end up booting directly from the 2TB, and wouldn't need that 15GB drive at all.
|
||||
|
||||
3. Create additional folders on the 2TB drive and mount them within your fstab into whatever directories on your / drive that need it most. This could be your /usr, /var, /etc, or even /home - depending on exactly which directories are being overloaded most. You'd then have to copy all data from your source 15GB drive folders (recursively, including subdirectories & permissions) to the respective new folder on the 2TB drive. This would be by far the most complex, and I wouldn't recommend it unless you have a good deal of experience working in the terminal along with a very good understanding of how Linux-like file systems work.
|
||||
|
||||
The fact is that unless your program is 100% self-contained with *all* of the dependencies in a single folder, you're likely to have bits & pieces installed in a variety of locations. You're not going to successfully move an application to a new location without going into each & every piece of that application to map out their relationship to one another, and adjusting accordingly. This would also permanently screw up your ability to update that application down the road. It is far better to either reinstall that app (if you have the ability to choose a target location) or to simply accept the program's structure and find a way to make space for it.
|
||||
|
||||
4. One other option - - depending on how much data you have/how much time you're willing to spend backing up or re-downloading - - re-install Mint directly onto that 2TB drive. This would be the cleanest option, and would avoid having to muck around with changing hardware around or playing with partitions. We don't know what programs & applications you have, or really anything at this point about your hardware & level of experience....but that would be the #1 thing to consider, in my opinion?
|
||||
```
|
||||
|
||||
- With Partition
|
||||
|
||||
Installing programs on another drive in Linux is possible, and it can be useful if you want to manage disk space efficiently or have specific storage requirements. The steps to achieve this may vary slightly depending on your Linux distribution, but the general process is as follows:
|
||||
|
||||
1. **Partition and Format the Drive:**
|
||||
If the drive is not already partitioned and formatted, you need to do that first. Use tools like **`fdisk`**, **`parted`**, or **`gparted`** to create a new partition on the drive and then format it with an appropriate file system like ext4.
|
||||
2. **Mount the Drive:**
|
||||
Once the drive is formatted, you need to mount it to a directory in your file system. Choose a suitable mount point, create a directory (if it doesn't already exist), and mount the new partition using the **`mount`** command. For example:
|
||||
|
||||
```bash
|
||||
bashCopy code
|
||||
sudo mount /dev/sdXY /mnt/my_new_drive
|
||||
|
||||
```
|
||||
|
||||
Replace **`/dev/sdXY`** with the correct partition identifier, and **`/mnt/my_new_drive`** with your chosen mount point.
|
||||
|
||||
3. **Configure the Fstab File (optional):**
|
||||
To mount the drive automatically at boot, you can add an entry to the **`/etc/fstab`** file. Open the file with a text editor (with root privileges) and add a line like this:
|
||||
|
||||
```bash
|
||||
bashCopy code
|
||||
/dev/sdXY /mnt/my_new_drive ext4 defaults 0 0
|
||||
|
||||
```
|
||||
|
||||
Again, replace **`/dev/sdXY`** and **`/mnt/my_new_drive`** with your partition and mount point.
|
||||
|
||||
4. **Install Programs to the New Drive:**
|
||||
When you install new programs, use the package manager of your distribution to specify the custom installation path on the new drive. For example, with **`apt`** (used in Debian-based systems), you can use the **`o`** option to set the installation path:
|
||||
|
||||
```arduino
|
||||
arduinoCopy code
|
||||
sudo apt-get install package_name -o dir::cache=/mnt/my_new_drive
|
||||
|
||||
```
|
||||
|
||||
This will install **`package_name`** on the specified path.
|
||||
|
||||
|
||||
Remember to adjust the commands according to your specific drive and mount point settings. Always be cautious when working with partitions and the filesystem, as it can lead to data loss if not done properly.
|
||||
|
||||
Additionally, if your intent is to move an already-installed program to another drive, it may be more complex and require additional steps depending on the application. In such cases, it is often simpler to reinstall the program with the custom installation path as described above.
|
||||
|
||||
- Without partition
|
||||
|
||||
Yes, you can install programs on another drive without creating a separate partition by using symbolic links or bind mounts. This method allows you to create a link from the original program directory to a directory on the other drive. This way, the program will appear to be installed on the primary drive, but its files will actually reside on the secondary drive.
|
||||
|
||||
Here's how you can do it using symbolic links or bind mounts:
|
||||
|
||||
**Symbolic Links:**
|
||||
|
||||
1. First, create a directory on the other drive where you want to store the program's files. For example:
|
||||
|
||||
```bash
|
||||
bashCopy code
|
||||
sudo mkdir /mnt/my_new_drive/my_programs
|
||||
|
||||
```
|
||||
|
||||
2. Next, install the program as you would normally do. Let's assume the program is installed in the default location, such as **`/usr/bin/my_program`**.
|
||||
3. Move the program's files to the directory on the other drive using **`mv`**:
|
||||
|
||||
```bash
|
||||
bashCopy code
|
||||
sudo mv /usr/bin/my_program /mnt/my_new_drive/my_programs/
|
||||
|
||||
```
|
||||
|
||||
4. Create a symbolic link from the original location to the new location on the other drive:
|
||||
|
||||
```bash
|
||||
bashCopy code
|
||||
sudo ln -s /mnt/my_new_drive/my_programs/my_program /usr/bin/my_program
|
||||
|
||||
```
|
||||
|
||||
|
||||
Now, when you run **`my_program`**, it will execute the program from the other drive even though the link is in the usual location.
|
||||
|
||||
**Bind Mounts:**
|
||||
|
||||
1. Create a directory on the other drive where you want to store the program's files, similar to the previous method.
|
||||
2. Install the program as usual.
|
||||
3. Instead of using symbolic links, you can mount the new directory over the original program directory using a bind mount. First, unmount the directory if it's already mounted:
|
||||
|
||||
```bash
|
||||
|
||||
sudo umount /usr/bin/my_program
|
||||
|
||||
```
|
||||
|
||||
4. Mount the new directory over the original program directory using the bind mount:
|
||||
|
||||
```bash
|
||||
|
||||
sudo mount --bind /mnt/my_new_drive/my_programs/my_program /usr/bin/my_program
|
||||
|
||||
```
|
||||
|
||||
5. Update the **`/etc/fstab`** file to ensure the bind mount is persistent across reboots. Add the following line:
|
||||
|
||||
```bash
|
||||
|
||||
/mnt/my_new_drive/my_programs/my_program /usr/bin/my_program none bind 0 0
|
||||
|
||||
```
|
||||
|
||||
|
||||
Remember to replace **`/mnt/my_new_drive/my_programs/my_program`** with the actual path to the program on the other drive.
|
||||
|
||||
Both methods achieve a similar outcome: installing the program on another drive without creating a separate partition. The symbolic link method is easier to set up, while bind mounts are more suitable for long-term and persistent use as they survive reboots.
|
||||
|
||||
- Battery drain
|
||||
|
||||
[https://fosspost.org/7-tips-to-reduce-battery-usage-on-linux/](https://fosspost.org/7-tips-to-reduce-battery-usage-on-linux/)
|
||||
|
||||
- Disabling peripherals
|
||||
|
||||
[https://askubuntu.com/questions/160945/is-there-a-way-to-disable-a-laptops-internal-keyboard](https://askubuntu.com/questions/160945/is-there-a-way-to-disable-a-laptops-internal-keyboard)
|
||||
|
||||
Sure, you can disable the internal keyboard on a Linux system while using an external keyboard. Here's a way to do it using the command line. Please note that you might need root (administrator) privileges to perform some of these actions.
|
||||
|
||||
1. **Identify the internal keyboard device:**
|
||||
|
||||
Open a terminal and enter the following command to list input devices:
|
||||
|
||||
```bash
|
||||
bashCopy code
|
||||
xinput list
|
||||
|
||||
```
|
||||
|
||||
Look for the entry corresponding to your internal keyboard. It will be listed along with its ID number.
|
||||
|
||||
2. **Disable the internal keyboard:**
|
||||
|
||||
Once you have identified the ID of your internal keyboard, you can use the following command to disable it:
|
||||
|
||||
```bash
|
||||
bashCopy code
|
||||
xinput float <internal_keyboard_id>
|
||||
|
||||
```
|
||||
|
||||
Replace **`<internal_keyboard_id>`** with the actual ID of your internal keyboard.
|
||||
|
||||
3. **Re-enable the internal keyboard:**
|
||||
|
||||
If you want to re-enable the internal keyboard later, you can use the following command:
|
||||
|
||||
```bash
|
||||
bashCopy code
|
||||
xinput reattach <internal_keyboard_id> <master_id>
|
||||
|
||||
```
|
||||
|
||||
Replace **`<internal_keyboard_id>`** with the ID of your internal keyboard and **`<master_id>`** with the ID of the master device (usually the external keyboard or a virtual core device).
|
||||
|
||||
|
||||
Please note that these changes will not persist across reboots. If you want the internal keyboard to remain disabled even after restarting your system, you might need to create a script that runs these commands during startup.
|
||||
|
||||
Remember that working with input devices can have implications, and disabling devices might lead to unexpected behaviors. Make sure you have a way to revert the changes if needed.
|
||||
|
||||
- Download manager
|
||||
|
||||
https://itsfoss.com/best-download-managers-linux/?fbclid=IwAR07vrVKSzaMZz5WNPo8KRjAA6VfX-bYPVnLe8IiU9Yi_YJ4wH0ZaijncZ8
|
||||
|
||||
- More apps
|
||||
|
||||
|
||||
https://itsfoss.com/best-ubuntu-apps/
|
||||
|
||||
https://www.geeksmint.com/awesome-linux-software/
|
||||
|
||||
- Cons of linux
|
||||
1. Consumes more battery because its drivers are not optimised as hardware firmwares are not open source but windows has a deal
|
||||
2. Audio and video driver are not that good
|
||||
3. hibernate is disabled by default
|
||||
4. no backward compatibility
|
||||
5. Not all softwares are available for Linux
|
||||
6. Fragmentation
|
||||
- Pirated gaming
|
||||
|
||||
Lutris
|
||||
|
||||
- lightweight distros
|
||||
|
||||
[https://itsfoss.com/lightweight-linux-beginners/#5-bodhi-linux](https://itsfoss.com/lightweight-linux-beginners/#5-bodhi-linux)
|
||||
|
||||
- Appimage
|
||||
|
||||
`chmod a+x <appimageFile>`
|
||||
|
||||
- Resizing partition
|
||||
|
||||
[https://www.youtube.com/watch?v=Kyz9x71gEPI](https://www.youtube.com/watch?v=Kyz9x71gEPI)
|
||||
|
||||
[https://e.pcloud.link/publink/show?code=XZWaeWZbzlFCCXrg0mX6XFcsNXvykHLqNkk](https://e.pcloud.link/publink/show?code=XZWaeWZbzlFCCXrg0mX6XFcsNXvykHLqNkk)
|
||||
|
||||
[https://sdrive.app/s/xnwhq1znzhn8kvyi3a9j71zo](https://sdrive.app/s/xnwhq1znzhn8kvyi3a9j71zo)
|
||||
|
||||
[https://files.sdrive.app/6e9bb95b-7524-437a-9c6e-54974f58b3fd.mp4](https://files.sdrive.app/6e9bb95b-7524-437a-9c6e-54974f58b3fd.mp4)
|
||||
|
||||
- WinRAR
|
||||
|
||||
[https://www.win-rar.com/download.html?&L=0](https://www.win-rar.com/download.html?&L=0)
|
||||
|
||||
You can extract a RAR file that is password protected on Linux with a utility called `unrar`
|
||||
|
||||
```
|
||||
1 sudo apt install unrar
|
||||
2
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
1 # provide a password with -p
|
||||
2 unrar e -pPASSWORD FILE.rar
|
||||
3
|
||||
|
||||
```
|
||||
|
||||
To just extract a file that has no password, only pass the `e` flag
|
||||
|
||||
```
|
||||
1 unrar e FILE.rar
|
||||
|
||||
```
|
||||
|
||||
[rarlinux-x64-623.tar.gz](../../_resources/rarlinux-x64-623.tar.gz)
|
||||
|
||||
- Portable firefox
|
||||
|
||||
[https://www.airaghi.net/en/2017/03/22/install-mozilla-firefox-portable-on-linux/](https://www.airaghi.net/en/2017/03/22/install-mozilla-firefox-portable-on-linux/)
|
||||
|
||||
- Recently installed
|
||||
1. docker images
|
||||
2. golang
|
||||
3. libsecret
|
||||
- Disable bluetooth on startup
|
||||
|
||||
For this ubuntu edit `/etc/bluetooth/main.conf` and find the line
|
||||
|
||||
```
|
||||
AutoEnable=true
|
||||
|
||||
```
|
||||
|
||||
and replace it with:
|
||||
|
||||
```
|
||||
AutoEnable=false
|
||||
```
|
||||
|
||||
- NordVpn
|
||||
|
||||
sign the key by downloading asc from
|
||||
|
||||
[https://repo.nordvpn.com/gpg/nordvpn_public.asc](https://repo.nordvpn.com/gpg/nordvpn_public.asc)
|
||||
|
||||
then
|
||||
|
||||
`sudo apt-key add nordvpn-public-key.asc`
|
||||
|
||||
`sudo nano /etc/apt/sources.list.d/nordvpn.list`
|
||||
|
||||
`deb [arch=amd64 signed-by=/usr/share/keyrings/nordvpn-archive-keyring.gpg]`
|
||||
|
||||
then download .deb file from here ‘[https://repo.nordvpn.com/deb/nordvpn/debian/pool/main/nordvpn_3.16.6_i386.deb](https://repo.nordvpn.com/deb/nordvpn/debian/pool/main/nordvpn_3.16.6_i386.deb)’
|
||||
|
||||
or
|
||||
|
||||
[https://file.lu/d/1noK](https://file.lu/d/1noK)
|
||||
|
||||
- Login
|
||||
- type `nordvpn login` into the cli
|
||||
- proceed through the browser
|
||||
- once you've logged in copy the link where it says "return to the app" (it should be something like `nordvpn://login` etc)
|
||||
- go back to cli and type `nordvpn login --callback "pasted-url-from-before"` (pay attention to quote the url!)
|
||||
- now you're logged in
|
||||
- connect
|
||||
|
||||
`nordvpn connect <country_name>` (no need of country code and server address)
|
||||
|
||||
- suspend/sleep
|
||||
|
||||
[https://askubuntu.com/questions/543921/authentication-required-before-suspend](https://askubuntu.com/questions/543921/authentication-required-before-suspend)
|
||||
|
||||
1. In command line run:
|
||||
|
||||
```
|
||||
locate -b org.freedesktop.login1.policy
|
||||
|
||||
```
|
||||
|
||||
The found file is
|
||||
|
||||
```
|
||||
/usr/share/polkit-1/actions/org.freedesktop.login1.policy
|
||||
|
||||
```
|
||||
|
||||
2. In the file, near line
|
||||
|
||||
```xml
|
||||
<action id="org.freedesktop.login1.suspend">
|
||||
|
||||
```
|
||||
|
||||
check these:
|
||||
|
||||
```xml
|
||||
<defaults>
|
||||
<allow_any>yes</allow_any>
|
||||
<allow_inactive>yes</allow_inactive>
|
||||
<allow_active>yes</allow_active>
|
||||
</defaults>
|
||||
```
|
||||
|
|
@ -0,0 +1,626 @@
|
|||
# NodeJS
|
||||
|
||||
- Executable for nodejs app
|
||||
|
||||
[https://www.youtube.com/watch?v=50f6y-npKAY](https://www.youtube.com/watch?v=50f6y-npKAY)
|
||||
|
||||
`npm i -g pkg`
|
||||
|
||||
`pkg app.js`
|
||||
|
||||
[https://www.youtube.com/watch?v=crnaBzztX44](https://www.youtube.com/watch?v=crnaBzztX44)
|
||||
|
||||
[https://www.npmjs.com/package/pkg](https://www.npmjs.com/package/pkg)
|
||||
|
||||
in package.json add:
|
||||
|
||||
```json
|
||||
|
||||
"pkg": {
|
||||
"scripts": "build/**/*.js",
|
||||
"assets": ["views/**/*","public/**","build/**"],
|
||||
"targets": [ "node14-win-x64" ]
|
||||
}
|
||||
```
|
||||
|
||||
Now type:
|
||||
|
||||
`pkg app.js -c package.json`
|
||||
|
||||
this will create the exe file. In assets resources is assigned like build/** so that all build folder is included as its front end in smart brain app. if we have images folder then include that too.
|
||||
|
||||
- converting callback to async/await
|
||||
|
||||
```jsx
|
||||
const promiseSetTimeOut = (time) => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, time);
|
||||
});
|
||||
};
|
||||
|
||||
// or
|
||||
// delay.js
|
||||
export function delay(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- apk version fo nodejs app
|
||||
|
||||
[Apache Cordova app development setup guide - Andrés Zsögön (andreszsogon.com)](https://www.andreszsogon.com/setting-up-your-environment-for-apache-cordova-apps/)
|
||||
|
||||
[https://cordova.apache.org/docs/en/3.5.0/guide/cli/index.html](https://cordova.apache.org/docs/en/3.5.0/guide/cli/index.html)
|
||||
|
||||
expressjs in mobile:
|
||||
|
||||
[https://www.sitepoint.com/how-to-run-node-js-with-express-on-mobile-devices/](https://www.sitepoint.com/how-to-run-node-js-with-express-on-mobile-devices/)
|
||||
|
||||
[https://github.com/node-on-mobile/node-on-android](https://github.com/node-on-mobile/node-on-android)
|
||||
|
||||
- Exposing localhost to internet for testing
|
||||
|
||||
```jsx
|
||||
const localtunnel = require('localtunnel');
|
||||
|
||||
(async () => {
|
||||
const tunnel = await localtunnel({ port: 80 });
|
||||
|
||||
// the assigned public url for your tunnel
|
||||
// i.e. https://abcdefgjhij.localtunnel.me
|
||||
// tunnel.url;
|
||||
console.log('url: ',tunnel.url)
|
||||
|
||||
tunnel.on('close', () => {
|
||||
// tunnels are closed
|
||||
});
|
||||
})();
|
||||
```
|
||||
|
||||
Ngrok:
|
||||
|
||||
Install ngrok or add ngrok.exe file in environment path from [https://ngrok.com/download](https://ngrok.com/download)
|
||||
|
||||
If local nodejs app is started in port number say 3000 then type
|
||||
|
||||
`ngrok http 3000`
|
||||
|
||||
public url wil be printed in terminal or access by [http://localhost:4040](http://localhost:4040/)
|
||||
|
||||
|
||||
[NodeGUI](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/NodeJS%206d499253059041d699e2e6fa36ded013/NodeGUI%20ac8ad0b3e1a74e0ca752c60add16e6ce.md)
|
||||
|
||||
- Extract metadata
|
||||
|
||||
[https://www.npmjs.com/package/metadata-scraper?activeTab=readme](https://www.npmjs.com/package/metadata-scraper?activeTab=readme)
|
||||
|
||||
[](https://www.npmjs.com/package/metadata-scraper?activeTab=readme)
|
||||
|
||||
[https://www.npmjs.com/package/page-metadata-parser](https://www.npmjs.com/package/page-metadata-parser)
|
||||
|
||||
[https://www.scrapingbee.com/blog/node-fetch/](https://www.scrapingbee.com/blog/node-fetch/)
|
||||
|
||||
- Page scrapper
|
||||
|
||||
browser as service : [https://www.browserless.io/blog/2022/05/31/youtube-scraper/](https://www.browserless.io/blog/2022/05/31/youtube-scraper/)
|
||||
|
||||
[https://www.demo2s.com/node.js/node-js-url-project-playlist-scraper-takes-a-youtube-playlist-url-gi.html](https://www.demo2s.com/node.js/node-js-url-project-playlist-scraper-takes-a-youtube-playlist-url-gi.html)
|
||||
|
||||
- for lazy loading content(which render when we scroll down to that):
|
||||
|
||||
[https://stackoverflow.com/questions/51529332/puppeteer-scroll-down-until-you-cant-anymore](https://stackoverflow.com/questions/51529332/puppeteer-scroll-down-until-you-cant-anymore)
|
||||
|
||||
```jsx
|
||||
const puppeteer = require('puppeteer');
|
||||
|
||||
(async () => {
|
||||
const browser = await puppeteer.launch({
|
||||
headless: false
|
||||
});
|
||||
const page = await browser.newPage();
|
||||
await page.goto('https://www.yoursite.com');
|
||||
await page.setViewport({
|
||||
width: 1200,
|
||||
height: 800
|
||||
});
|
||||
|
||||
await autoScroll(page);
|
||||
|
||||
await page.screenshot({
|
||||
path: 'yoursite.png',
|
||||
fullPage: true
|
||||
});
|
||||
|
||||
await browser.close();
|
||||
})();
|
||||
|
||||
async function autoScroll(page){
|
||||
await page.evaluate(async () => {
|
||||
await new Promise((resolve) => {
|
||||
var totalHeight = 0;
|
||||
var distance = 100;
|
||||
var timer = setInterval(() => {
|
||||
var scrollHeight = document.body.scrollHeight;
|
||||
window.scrollBy(0, distance);
|
||||
totalHeight += distance;
|
||||
// scrollheight is subtracted as innerheight is portion
|
||||
// only rendered so remaining portion to be scrolled down
|
||||
if(totalHeight >= scrollHeight - window.innerHeight){
|
||||
clearInterval(timer);
|
||||
resolve();
|
||||
}
|
||||
}, 100);
|
||||
});
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
- Download any file from web server
|
||||
|
||||
[https://www.npmjs.com/package/nodejs-file-downloader](https://www.npmjs.com/package/nodejs-file-downloader)
|
||||
|
||||
- Alternative of axios
|
||||
|
||||
[https://stackoverflow.com/questions/13864983/how-to-post-multipart-form-data-with-node-js-superagent](https://stackoverflow.com/questions/13864983/how-to-post-multipart-form-data-with-node-js-superagent)
|
||||
|
||||
```jsx
|
||||
const superagent = require('superagent');
|
||||
superagent
|
||||
.post('https://www.y2mate.com/mates/en423/analyze/ajax')
|
||||
// .send(formData) // sends a JSON post body
|
||||
.set('accept', 'application/json')
|
||||
.field('url',url)
|
||||
.field('q_auto',0)
|
||||
.field('ajax',2)
|
||||
|
||||
.end(async (err, res) => {
|
||||
// same as finally means both then and catch
|
||||
}
|
||||
```
|
||||
|
||||
or for json:
|
||||
|
||||
```jsx
|
||||
superagent
|
||||
.post('/api/pet')
|
||||
.send({ name: 'Manny', species: 'cat' }) // sends a JSON post body
|
||||
.set('X-API-Key', 'foobar')
|
||||
.set('accept', 'json')
|
||||
.end((err, res) => {
|
||||
// Calling the end function will send the request
|
||||
});
|
||||
|
||||
// promise with then/catch
|
||||
superagent.post('/api/pet').then(console.log).catch(console.error);
|
||||
```
|
||||
|
||||
- Inspect nodejs app to Chrome
|
||||
|
||||
`node inspect app.js`
|
||||
|
||||
In browser type
|
||||
|
||||
`chrome://inspect` and open dedicated DevTools for Node
|
||||
|
||||
- Update nodejs and npm
|
||||
|
||||
[https://www.geeksforgeeks.org/how-to-update-node-js-and-npm-to-next-version/](https://www.geeksforgeeks.org/how-to-update-node-js-and-npm-to-next-version/)
|
||||
|
||||
- Taking input in synchronous way
|
||||
|
||||
```jsx
|
||||
// to take input from user
|
||||
const readlineSync = require('readline-sync');
|
||||
|
||||
// Wait for user's response.
|
||||
const phrase = readlineSync.question('Type a phrase (or quit to exit program): ');
|
||||
|
||||
```
|
||||
|
||||
- async fs without callback hell
|
||||
|
||||
[https://www.youtube.com/watch?v=msnTtrx2C4s](https://www.youtube.com/watch?v=msnTtrx2C4s)
|
||||
|
||||
- file system cache in nodejs
|
||||
|
||||
[https://www.npmjs.com/package/file-system-cache](https://www.npmjs.com/package/file-system-cache)
|
||||
|
||||
Example:
|
||||
|
||||
```jsx
|
||||
// const NodeCache=require('node-cache')
|
||||
// const myCache=new NodeCache();
|
||||
const FileSystemCache_1 =require('file-system-cache')
|
||||
|
||||
const options={basePath: "./.cache", // Optional. Path where cache files are stored (default).
|
||||
ns: "my-namespace" // Optional. A grouping namespace for items.
|
||||
}
|
||||
const cache=new FileSystemCache_1.FileSystemCache(options)
|
||||
|
||||
const heavyComputation=()=>{
|
||||
let temp = 0;
|
||||
for(let i=0; i<100000; i++)
|
||||
temp = (Math.random()*5342)%i;
|
||||
return 123;
|
||||
}
|
||||
|
||||
const main=async()=>{
|
||||
if(await cache.fileExists('key'))
|
||||
{
|
||||
console.log('res: ',await cache.get('key'))
|
||||
}
|
||||
else{
|
||||
let res= heavyComputation()
|
||||
cache.set('key',res)
|
||||
console.log('Value not present performing calculation')
|
||||
|
||||
console.log('res2: ',res)
|
||||
}
|
||||
|
||||
}
|
||||
main()
|
||||
```
|
||||
|
||||
some changes in `./node_modules/file-system-cache/lib/index.js` :
|
||||
|
||||
```jsx
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.FileSystemCache = void 0;
|
||||
const FileSystemCache_1 = require("./FileSystemCache");
|
||||
Object.defineProperty(exports, "FileSystemCache", { enumerable: true, get: function () { return FileSystemCache_1.FileSystemCache; } });
|
||||
const Cache= (options) => new FileSystemCache_1.FileSystemCache(options);
|
||||
exports.default = FileSystemCache_1
|
||||
```
|
||||
|
||||
- Mockable.io
|
||||
|
||||
used by front end developers to create rest api
|
||||
|
||||
- read only file system
|
||||
|
||||
When working on read only file system use the /tmp to perform write functions.
|
||||
|
||||
`fs.writeFileSync("/tmp/users.json", JSON.stringify(users))`
|
||||
|
||||
|
||||
- state management in nodejs
|
||||
|
||||
```jsx
|
||||
//state.js file
|
||||
|
||||
class State {
|
||||
constructor() {
|
||||
this.currentState = false;
|
||||
this.data = null;
|
||||
this.setState = (st) => {
|
||||
this.currentState=st;
|
||||
};
|
||||
this.setData = (da) => {
|
||||
this.data = da;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const appState = new State();
|
||||
module.exports = appState;
|
||||
```
|
||||
|
||||
```jsx
|
||||
const appState = require("./state");
|
||||
const PORT = 3000;
|
||||
|
||||
const promiseSetTimeOut = (time) => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, time);
|
||||
});
|
||||
};
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(express.static(__dirname + "/public"));
|
||||
|
||||
app.get("/getData", (req, res) => {
|
||||
res.json(appState.currentState);
|
||||
});
|
||||
|
||||
app.put("/updateData/:st", (req, res) => {
|
||||
const { st } = req.params;
|
||||
let stBool = false;
|
||||
let actualValue;
|
||||
if (st == "1") {
|
||||
stBool = true;
|
||||
actualValue=st
|
||||
}
|
||||
|
||||
res.json("updating");
|
||||
const promiseID = promiseSetTimeOut(5000);
|
||||
promiseID.then(() => {
|
||||
// console.log("updated ",stBool);
|
||||
appState.setState(stBool);
|
||||
appState.setData(actualValue);
|
||||
console.log(appState);
|
||||
});
|
||||
});
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log("listening");
|
||||
});
|
||||
```
|
||||
|
||||
- Polling for limited timeout problem
|
||||
|
||||
[https://www.npmjs.com/package/http-delayed-response](https://www.npmjs.com/package/http-delayed-response)
|
||||
|
||||
[https://spin.atomicobject.com/2018/05/15/extending-heroku-timeout-node/](https://spin.atomicobject.com/2018/05/15/extending-heroku-timeout-node/)
|
||||
|
||||
- Deta
|
||||
|
||||
[https://deta.space/docs/en/quickstart-guides/node](https://deta.space/docs/en/quickstart-guides/node)
|
||||
https://deta.space/docs/en/build/quick-starts/node
|
||||
https://deta.space/builder : to go to builder page
|
||||
**Uninstalling deta**:
|
||||
It makes a hidden directory named as ".detaspace" in home directory just delete it .
|
||||
|
||||
|
||||
to open setting: [https://deta.space/?tty_open=settings](https://deta.space/?tty_open=settings)
|
||||
|
||||
- Installing from github instead of npm library
|
||||
|
||||
`"ytdl-core": "git+https://github.com/khlevon/node-ytdl-core.git#v4.11.4-patch.2”`
|
||||
|
||||
`npm -i [https://github.com/khlevon/node-ytdl-core#v4.11.4-patch.2](https://github.com/khlevon/node-ytdl-core#v4.11.4-patch.2) —no-audit`
|
||||
|
||||
- Socket
|
||||
|
||||
backend
|
||||
|
||||
```jsx
|
||||
const WebSocket = require("ws");
|
||||
|
||||
// creating a websocket connection at port 8080
|
||||
const server = new WebSocket.Server({ port: 8080 });
|
||||
|
||||
// this callback function will respond once client connect to ws://localhost:8080
|
||||
server.on("connection", (socket) => {
|
||||
console.log("connected");
|
||||
|
||||
// this one respond once client send back a message here
|
||||
socket.on("message", (message, isString) => {
|
||||
// by default message is in buffer si convert it to string
|
||||
let msg = isString ? message : message.toString();
|
||||
console.log("message: ", msg);
|
||||
|
||||
// sending back the same message which was sent here by client
|
||||
socket.send(msg);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
frontend
|
||||
|
||||
```jsx
|
||||
// ws protocol is used instead of http
|
||||
const socket = new WebSocket("ws://localhost:8080");
|
||||
|
||||
// this callback function will respond once server send back a message here
|
||||
socket.onmessage = (e) => {
|
||||
console.log("Message: ", e.data);
|
||||
};
|
||||
|
||||
document.querySelector("button").onclick = () => {
|
||||
// send method to send the message to server
|
||||
socket.send("helo");
|
||||
};
|
||||
```
|
||||
|
||||
- socket.io
|
||||
|
||||
high level library which uses ws to provide support for multiple clients and broadcasting
|
||||
|
||||
backend
|
||||
|
||||
```jsx
|
||||
const PORT = process.env.PORT || 8080;
|
||||
|
||||
const httpServer = require("http").createServer();
|
||||
const socketIO = require("socket.io");
|
||||
|
||||
// linking with httpserver
|
||||
const io = socketIO(httpServer, {
|
||||
cors: { origin: "*" },
|
||||
});
|
||||
|
||||
// when client connects to the server
|
||||
io.on("connection", (socket) => {
|
||||
console.log(`user connected ${socket.id}`);
|
||||
|
||||
// when listening to custom event named 'message'
|
||||
socket.on("message", (message) => {
|
||||
|
||||
// here using socket.boradcast.emit will send message to all client except the one who originally sent to server
|
||||
socket.broadcast.emit(
|
||||
"message",
|
||||
`${socket.id.substr(0, 2)} said ${message}`
|
||||
);
|
||||
|
||||
// to send to all including OP, use io.emit
|
||||
// and for particular client use
|
||||
// io.to(socket.id). emit("event", data);
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
httpServer.listen(PORT, () => {
|
||||
console.log("listening");
|
||||
});
|
||||
```
|
||||
|
||||
frontend
|
||||
|
||||
```jsx
|
||||
const socket = io("ws://localhost:8080");
|
||||
|
||||
const list = document.querySelector("#msgList");
|
||||
const inputEle = document.querySelector("#chatInput");
|
||||
|
||||
// when listening to custom event named 'message'
|
||||
socket.on("message", (msg) => {
|
||||
const li = document.createElement("li");
|
||||
li.innerText = msg;
|
||||
list.appendChild(li);
|
||||
});
|
||||
|
||||
document.querySelector("#sendBtn").onclick = () => {
|
||||
const text = inputEle.value;
|
||||
|
||||
// emitting custom event named 'message' and passing the paramter $text
|
||||
socket.emit("message", text);
|
||||
const li = document.createElement("li");
|
||||
li.innerText = `you said ${text}`;
|
||||
list.appendChild(li);
|
||||
inputEle.value = "";
|
||||
};
|
||||
```
|
||||
|
||||
- AES file encryption
|
||||
|
||||
[https://github.com/AKASHAorg/easy-web-crypto](https://github.com/AKASHAorg/easy-web-crypto)
|
||||
|
||||
```jsx
|
||||
function processFile(evt) {
|
||||
var file = evt.target.files[0],
|
||||
reader = new FileReader();
|
||||
|
||||
reader.onload = function(e) {
|
||||
var data = e.target.result,
|
||||
iv = crypto.getRandomValues(new Uint8Array(16));
|
||||
|
||||
crypto.subtle.generateKey({ 'name': 'AES-CBC', 'length': 256 }, false, ['encrypt', 'decrypt'])
|
||||
.then(key => crypto.subtle.encrypt({ 'name': 'AES-CBC', iv }, key, data) )
|
||||
.then(encrypted => {
|
||||
console.log(encrypted);
|
||||
alert('The encrypted data is ' + encrypted.byteLength + ' bytes long'); // encrypted is an ArrayBuffer
|
||||
})
|
||||
.catch(console.error);
|
||||
}
|
||||
|
||||
reader.readAsArrayBuffer(file);
|
||||
```
|
||||
|
||||
`<input type="file" id="file-upload" onchange="processFile(event)">`
|
||||
|
||||
- more
|
||||
|
||||
[https://stackoverflow.com/questions/60520526/aes-encryption-and-decryption-of-files-using-crypto-js](https://stackoverflow.com/questions/60520526/aes-encryption-and-decryption-of-files-using-crypto-js)
|
||||
|
||||
Slicing files to chunks
|
||||
|
||||
[https://stackoverflow.com/questions/29731329/cryptojs-sha256-large-file-progressive-checksum/62824083#62824083](https://stackoverflow.com/questions/29731329/cryptojs-sha256-large-file-progressive-checksum/62824083#62824083)
|
||||
|
||||
```jsx
|
||||
function encrypt(input) {
|
||||
var file = input.files[0];
|
||||
var reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
var key = "1234567887654321";
|
||||
var wordArray = CryptoJS.lib.WordArray.create(reader.result); // Convert: ArrayBuffer -> WordArray
|
||||
var encrypted = CryptoJS.AES.encrypt(wordArray, key).toString(); // Encryption: I: WordArray -> O: -> Base64 encoded string (OpenSSL-format)
|
||||
|
||||
var fileEnc = new Blob([encrypted]); // Create blob from string
|
||||
|
||||
var a = document.createElement("a");
|
||||
var url = window.URL.createObjectURL(fileEnc);
|
||||
var filename = file.name + ".enc";
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
function convertWordArrayToUint8Array(wordArray) {
|
||||
var arrayOfWords = wordArray.hasOwnProperty("words") ? wordArray.words : [];
|
||||
var length = wordArray.hasOwnProperty("sigBytes") ? wordArray.sigBytes : arrayOfWords.length * 4;
|
||||
var uInt8Array = new Uint8Array(length), index=0, word, i;
|
||||
for (i=0; i<length; i++) {
|
||||
word = arrayOfWords[i];
|
||||
uInt8Array[index++] = word >> 24;
|
||||
uInt8Array[index++] = (word >> 16) & 0xff;
|
||||
uInt8Array[index++] = (word >> 8) & 0xff;
|
||||
uInt8Array[index++] = word & 0xff;
|
||||
}
|
||||
return uInt8Array;
|
||||
}
|
||||
|
||||
function decrypt(input) {
|
||||
var file = input.files[0];
|
||||
var reader = new FileReader();
|
||||
reader.onload = () => {
|
||||
var key = "1234567887654321";
|
||||
|
||||
var decrypted = CryptoJS.AES.decrypt(reader.result, key); // Decryption: I: Base64 encoded string (OpenSSL-format) -> O: WordArray
|
||||
var typedArray = convertWordArrayToUint8Array(decrypted); // Convert: WordArray -> typed array
|
||||
|
||||
var fileDec = new Blob([typedArray]); // Create blob from typed array
|
||||
|
||||
var a = document.createElement("a");
|
||||
var url = window.URL.createObjectURL(fileDec);
|
||||
var filename = file.name.substr(0, file.name.length - 4) + ".dec";
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
```
|
||||
|
||||
Slicing
|
||||
|
||||
```jsx
|
||||
import CryptoJS from 'crypto-js';
|
||||
|
||||
class ChecksumService {
|
||||
|
||||
async sha256(file: File): Promise<string> {
|
||||
let sha256 = CryptoJS.algo.SHA256.create();
|
||||
const sliceSize = 10_485_760; // 10 MiB
|
||||
let start = 0;
|
||||
|
||||
while (start < file.size) {
|
||||
const slice: Uint8Array = await this.readSlice(file, start, sliceSize);
|
||||
const wordArray = CryptoJS.lib.WordArray.create(slice);
|
||||
sha256 = sha256.update(wordArray);
|
||||
start += sliceSize;
|
||||
}
|
||||
|
||||
sha256.finalize();
|
||||
|
||||
return sha256._hash.toString();
|
||||
}
|
||||
|
||||
private async readSlice(file: File, start: number, size: number): Promise<Uint8Array> {
|
||||
return new Promise<Uint8Array>((resolve, reject) => {
|
||||
const fileReader = new FileReader();
|
||||
const slice = file.slice(start, start + size);
|
||||
|
||||
fileReader.onload = () => resolve(new Uint8Array(fileReader.result as any));
|
||||
fileReader.onerror = reject;
|
||||
fileReader.readAsArrayBuffer(slice);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
- Tauri
|
||||
|
||||
[Download first_tauri.zip-423.8 MB](https://www.mediafire.com/file/m2jld5bq1adnxil/first_tauri.zip/file)
|
||||
|
||||
[Download linux_tauri.zip-574.9 MB](https://www.mediafire.com/file/q16pyty2nqkb9do/linux_tauri.zip/file)
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
# NodeGUI
|
||||
|
||||
[https://react.nodegui.org/](https://react.nodegui.org/)
|
||||
|
||||
nodegui installation as whole
|
||||
|
||||
[https://www.notion.so/notesharsh/study-private-aa2fff89ee2b4525a6028f9b16de137f#dc0e5ebfc97f45619a4f4573fae5172f](../../../undefined)
|
||||
|
||||
[](../../../undefined)
|
||||
|
||||
```
|
||||
git clone https://github.com/nodegui/react-nodegui-starter
|
||||
```
|
||||
|
||||
```
|
||||
cd react-nodegui-starter
|
||||
```
|
||||
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
```
|
||||
npm run dev
|
||||
```
|
||||
|
||||
```
|
||||
npm start
|
||||
```
|
||||
|
||||
for react nodegui preinstall requirements:
|
||||
|
||||
1: qt minimal framework(default no additional options)
|
||||
|
||||
2: visual studio 2017 and choose msvc 2017 build tools
|
||||
|
||||
3 and windows 8.1 sdk
|
||||
|
||||
- nodegui api
|
||||
|
||||
|
||||
[https://docs.nodegui.org/docs/api/generated/classes/qwidget/](https://docs.nodegui.org/docs/api/generated/classes/qwidget/)
|
||||
|
||||
[https://docs.nodegui.org/docs/api/generated/classes/qwidget/](https://docs.nodegui.org/docs/api/generated/classes/qwidget/)
|
||||
|
||||
- More
|
||||
|
||||
# Selectable Text
|
||||
|
||||
**Closed**
|
||||
|
||||
**[MistahMojo](https://github.com/MistahMojo)** opened this issue on Jun 20, 2020 · 5 comments
|
||||
|
||||
**Closed**
|
||||
|
||||
# **[Selectable Text](https://github.com/nodegui/react-nodegui/issues/236#top)#236**
|
||||
|
||||
**[MistahMojo](https://github.com/MistahMojo)** opened this issue on Jun 20, 2020 · 5 comments
|
||||
|
||||
# **Comments**
|
||||
|
||||
**Contributor**
|
||||
|
||||
### **[MistahMojo](https://github.com/MistahMojo)** commented [on Jun 20, 2020](https://github.com/nodegui/react-nodegui/issues/236#issue-642339668) • edited
|
||||
|
||||
Hello, is there a way to make the Text widget selectable by the user?
|
||||
|
||||
Is this a 'missing' feature or do the docs just not cover this?
|
||||
|
||||
---
|
||||
|
||||
**Collaborator**
|
||||
|
||||
### **[a7ul](https://github.com/a7ul)** commented [on Jun 20, 2020](https://github.com/nodegui/react-nodegui/issues/236#issuecomment-646983689) • edited
|
||||
|
||||
Hey **[@MistahMojo](https://github.com/MistahMojo)**Seems like textInteractionFlag is a property
|
||||
|
||||
In case of nodegui you could do:
|
||||
|
||||
```tsx
|
||||
import { QMainWindow, QLabel } from '@nodegui/nodegui';
|
||||
|
||||
const win = new QMainWindow();
|
||||
win.resize(500, 500);
|
||||
|
||||
const label = new QLabel();
|
||||
label.setText('Yolo 12321312 313123');
|
||||
label.setProperty('textInteractionFlags', 1);
|
||||
|
||||
win.setCentralWidget(label);
|
||||
win.show();
|
||||
(global as any).win = win;
|
||||
```
|
||||
|
||||
Where value `1` comes from [https://doc.qt.io/qt-5/qt.html#TextInteractionFlag-enum](https://doc.qt.io/qt-5/qt.html#TextInteractionFlag-enum)
|
||||
|
||||
---
|
||||
|
|
@ -0,0 +1,665 @@
|
|||
# React
|
||||
|
||||
[Links](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/React%205b9af27e2c194a4cb22a32306e53c39f/Links%208668d1c86d604b9b8ea3d865e2e39428.md)
|
||||
|
||||
- Forms of react for different devices
|
||||
|
||||
react-dom : web browser
|
||||
|
||||
react-native: mobile apps including android and ios
|
||||
|
||||
react-nodegui: for desktop apps
|
||||
|
||||
|
||||
[React app to mobile app](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/React%205b9af27e2c194a4cb22a32306e53c39f/React%20app%20to%20mobile%20app%2016113733577b4d2cbcaf3f7241.md)
|
||||
|
||||
[Creating react app to exe file](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/React%205b9af27e2c194a4cb22a32306e53c39f/Creating%20react%20app%20to%20exe%20file%209fd8b11fbb14409794a.md)
|
||||
|
||||
- React-router-dom
|
||||
|
||||
Creating structure for routes:
|
||||
|
||||
```jsx
|
||||
import { Route, Routes, Link, BrowserRouter as Router } from "react-router-dom";
|
||||
|
||||
const routing = (
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route path="/" element={<App />} />
|
||||
<Route path="/Similar/:name" element={<Similar />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
);
|
||||
|
||||
ReactDOM.render(
|
||||
// <React.StrictMode>
|
||||
routing,
|
||||
/* </React.StrictMode> */
|
||||
document.getElementById("root")
|
||||
);
|
||||
|
||||
// deleivering state to destination page:
|
||||
import {useNavigate} from 'react-router-dom';
|
||||
const navigate = useNavigate();
|
||||
navigate(`/Similar/${encodeURI(title)}`, {
|
||||
state: props,
|
||||
});
|
||||
|
||||
// getting state from destination page:
|
||||
import { useLocation } from "react-router-dom";
|
||||
const { state } = useLocation();
|
||||
const { poster_path, title, vote_average, overview, id } = state;
|
||||
```
|
||||
|
||||
- No value dynamic attributes in React
|
||||
|
||||
For attributes in jsx having no value like disabled in select element
|
||||
|
||||
for eg:
|
||||
|
||||
```html
|
||||
<select name="" id="brands" disabled >
|
||||
<option value="brands"></option>
|
||||
</select>
|
||||
```
|
||||
|
||||
If we want the disabled due to be dynamic means it should be disabled on basis of given condition then
|
||||
|
||||
```jsx
|
||||
<select
|
||||
name=""
|
||||
id="brands"
|
||||
onChange={selectBrand}
|
||||
disabled={isBrandDisabled}
|
||||
>
|
||||
```
|
||||
|
||||
Here isBrandDisabled is boolean value
|
||||
|
||||
- passing other parameters in a callback function for events like onclick or onchange
|
||||
|
||||
```jsx
|
||||
<input
|
||||
className="inputQty"
|
||||
type="number"
|
||||
name=""
|
||||
id=""
|
||||
defaultValue={0}
|
||||
onChange={(e)=>{
|
||||
func(e,arg1);
|
||||
}}
|
||||
```
|
||||
|
||||
- Caution for storing component in state
|
||||
|
||||
Its advisable to not store react component in state like
|
||||
|
||||
```jsx
|
||||
const [comp,setComp]= useState(null)
|
||||
|
||||
setComp(Comp)
|
||||
```
|
||||
|
||||
Here Comp is React component. Problem with this is when we try to pass setState hook or class method then setstate may not work as state may not store such complex things
|
||||
|
||||
- Practical example showing importance of keys
|
||||
|
||||
Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity:
|
||||
|
||||
For eg: If we have list of child components having their own state which are rendered dynamically according to the data which can be changed due to events.
|
||||
|
||||
If data is changed, suppose item is deleted so that particular component is deleted at position say 2. Then when re-rendering, component which was at position 3, will be in position 2. So now state of component which was in position 2, that state will be used as position is same.
|
||||
|
||||
**Proof:**
|
||||
|
||||
```jsx
|
||||
import React from 'https://cdn.skypack.dev/react';
|
||||
import ReactDOM from 'https://cdn.skypack.dev/react-dom';
|
||||
|
||||
const {useState} =React
|
||||
|
||||
const Item=(props)=>{
|
||||
const {item,setItems,items}=props
|
||||
const [qty,setQty]=useState(0)
|
||||
|
||||
return(
|
||||
<div className="item">
|
||||
<span>{item}: </span>
|
||||
<span>{qty}</span>
|
||||
|
||||
<button style={{marginLeft: '1rem'}} onClick={()=>{
|
||||
setQty(qty+1)
|
||||
}}>+</button>
|
||||
<button onClick={()=>{
|
||||
const newItems=items.filter((ele)=>ele!==item)
|
||||
setItems(newItems)
|
||||
}}>X</button>
|
||||
<br/>
|
||||
</div>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
// key={item}
|
||||
|
||||
const App = () => {
|
||||
|
||||
const [items,setItems]=useState (['strawberry','apple','orange','grapes','pear'])
|
||||
|
||||
const itemsarray=items.map((item)=>{
|
||||
return(
|
||||
<Item item={item} items={items} setItems={setItems}/>)
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
{itemsarray}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById("root"));
|
||||
```
|
||||
|
||||

|
||||
|
||||
After deleting 1st item:
|
||||
|
||||

|
||||
|
||||
As we can see state ‘qty’ dont get deleted as here component are identified only due to position. So we need to provide the key to uniquely identify them
|
||||
|
||||
```jsx
|
||||
import React from 'https://cdn.skypack.dev/react';
|
||||
import ReactDOM from 'https://cdn.skypack.dev/react-dom';
|
||||
|
||||
const {useState} =React
|
||||
|
||||
const Item=(props)=>{
|
||||
const {item,setItems,items}=props
|
||||
const [qty,setQty]=useState(0)
|
||||
|
||||
return(
|
||||
<div className="item">
|
||||
<span>{item}: </span>
|
||||
<span>{qty}</span>
|
||||
|
||||
<button style={{marginLeft: '1rem'}} onClick={()=>{
|
||||
setQty(qty+1)
|
||||
}}>+</button>
|
||||
<button onClick={()=>{
|
||||
const newItems=items.filter((ele)=>ele!==item)
|
||||
setItems(newItems)
|
||||
}}>X</button>
|
||||
<br/>
|
||||
</div>
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
const App = () => {
|
||||
|
||||
const [items,setItems]=useState (['strawberry','apple','orange','grapes','pear'])
|
||||
|
||||
const itemsarray=items.map((item)=>{
|
||||
return(
|
||||
<Item key={item} item={item} items={items} setItems={setItems}/>)
|
||||
})
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
{itemsarray}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById("root"));
|
||||
```
|
||||
|
||||

|
||||
|
||||
After deleting ‘strawberry’:
|
||||
|
||||

|
||||
|
||||
- render parent component when child state is changed.
|
||||
|
||||
Normally when parent component is re-rendered, child component also get rendered.
|
||||
|
||||
Proof:
|
||||
|
||||
```jsx
|
||||
import React from 'https://cdn.skypack.dev/react';
|
||||
import ReactDOM from 'https://cdn.skypack.dev/react-dom';
|
||||
// import {useState} from 'https://cdn.skypack.dev/react'
|
||||
|
||||
const {useState} =React
|
||||
|
||||
const Child=(props)=>{
|
||||
|
||||
const [state,setState]=useState(0)
|
||||
|
||||
console.log('Child component rendered')
|
||||
return(
|
||||
<div className="child">
|
||||
<div className="">Child</div>
|
||||
<button onClick={()=>{
|
||||
console.log('child button clicked')
|
||||
setState(state+1)
|
||||
}} className="">{state}</button>
|
||||
</div>
|
||||
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
const App = () => {
|
||||
const [state,setState]=useState(0)
|
||||
|
||||
console.log('\nParent component rendered')
|
||||
return (
|
||||
<div>
|
||||
<button onClick={()=>{
|
||||
console.log('Parent button clicked')
|
||||
setState(state+1)
|
||||
}}>{state}</button>
|
||||
<Child/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById("root"));
|
||||
```
|
||||
|
||||

|
||||
|
||||
To stop rerendering: use React.memo() while exporting child component in Child.js file
|
||||
|
||||
```jsx
|
||||
import React from "react";
|
||||
|
||||
function Child(props) {
|
||||
console.log("child component");
|
||||
return <div className="App">child Page</div>;
|
||||
}
|
||||
|
||||
export default React.memo(Child);
|
||||
```
|
||||
|
||||
When child component is updated then parent component is not updated as we can see from console output.
|
||||
|
||||
So to update the parent component when child component is updated.
|
||||
|
||||
If we want to rerender parent component for any child state changes then we can pass any state like render and setRender from parent to child and change that state in child component when child state changes thus updating parent component too.
|
||||
|
||||
```jsx
|
||||
const Child=({setRender,render})=>{
|
||||
|
||||
const [state,setState]=useState(0)
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
setRender(render+1)
|
||||
|
||||
}, [state])
|
||||
|
||||
console.log('Child component rendered')
|
||||
return(
|
||||
<div className="child">
|
||||
<div className="">Child</div>
|
||||
<button onClick={()=>{
|
||||
console.log('child button clicked')
|
||||
setState(state+1)
|
||||
}} className="">{state}</button>
|
||||
</div>
|
||||
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
const App = () => {
|
||||
const [state,setState]=useState(0)
|
||||
const [render,setRender]=useState(0)
|
||||
|
||||
console.log('\nParent component rendered')
|
||||
return (
|
||||
<div>
|
||||
<button onClick={()=>{
|
||||
console.log('Parent button clicked')
|
||||
setState(state+1)
|
||||
}}>{state}</button>
|
||||
<Child setRender={setRender} render={render}/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById("root"));
|
||||
```
|
||||
|
||||

|
||||
|
||||
- Animation
|
||||
|
||||
Tilt and Particles:
|
||||
|
||||

|
||||
|
||||
For GUI testing in particles.js use:
|
||||
|
||||
[https://vincentgarreau.com/particles.js/](https://vincentgarreau.com/particles.js/)
|
||||
|
||||
- tippyjs
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
- Equivalent of useEffect
|
||||
|
||||
For eg: using useeffect:
|
||||
|
||||
```jsx
|
||||
import { useState, useEffect, Fragment } from "react";
|
||||
import "./styles.css";
|
||||
|
||||
export default function App() {
|
||||
const [int, setInt] = useState(0);
|
||||
|
||||
useEffect(()=>{
|
||||
console.log(int)
|
||||
},[int])
|
||||
|
||||
const handleClick=()=>{
|
||||
setInt(int+1)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
<h1>Hello CodeSandbox</h1>
|
||||
<h2 onClick={handleClick}>Start editing to see some magic happen!</h2>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
same using componentDidUpdate()
|
||||
|
||||
```jsx
|
||||
import "./styles.css";
|
||||
|
||||
import {Component} from 'react'
|
||||
|
||||
class App extends Component
|
||||
{
|
||||
|
||||
constructor(){
|
||||
super()
|
||||
this.state={
|
||||
int: 0
|
||||
}
|
||||
// this.handleClick=this.handleClick.bind(this)
|
||||
}
|
||||
|
||||
handleClick=()=>{
|
||||
this.setState({int: this.state.int+1})
|
||||
// console.log(this.state.int)
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
console.log(this.state.int)
|
||||
}
|
||||
|
||||
// for checking props, prevProps is used instead of prevState
|
||||
componentDidUpdate(prevState){
|
||||
if(this.state.int!==prevState.int){
|
||||
console.log(this.state.int)
|
||||
}
|
||||
}
|
||||
|
||||
render(){
|
||||
return(
|
||||
|
||||
<div className="App">
|
||||
<h1>Hello CodeSandbox</h1>
|
||||
<h2 onClick={this.handleClick}>Start editing to see some magic happen!</h2>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
- bind() method
|
||||
|
||||
[https://www.freecodecamp.org/news/this-is-why-we-need-to-bind-event-handlers-in-class-components-in-react-f7ea1a6f93eb/](https://www.freecodecamp.org/news/this-is-why-we-need-to-bind-event-handlers-in-class-components-in-react-f7ea1a6f93eb/)
|
||||
|
||||
By default user defined methods in class components is not binded by default so we need to explicitly bind it.
|
||||
|
||||
```jsx
|
||||
class Foo extends React.Component{
|
||||
constructor( props ){
|
||||
super( props );
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
|
||||
handleClick(event){
|
||||
// your event handling logic
|
||||
}
|
||||
|
||||
render(){
|
||||
return (
|
||||
<button type="button"
|
||||
onClick={this.handleClick}>
|
||||
Click Me
|
||||
</button>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<Foo />,
|
||||
document.getElementById("app")
|
||||
);
|
||||
```
|
||||
|
||||
if bind is not used then this.handleclick wont be available.
|
||||
|
||||
- dispatch
|
||||
|
||||
[dispatch() is the method used to dispatch actions](https://redux.js.org/api/store#dispatchaction)
|
||||
and trigger state changes to the store. react-redux is simply trying to give you convenient access to it
|
||||
|
||||
- Lifescycle of useeffect,usestate and useref
|
||||
|
||||
First if any even changes state then state is changed causing component to re render so that new state value if used in DOM will be updated too
|
||||
|
||||
Then after component is re render, side effects in useEffect take place if specified state in array(2nd parameter changes)
|
||||
|
||||
Example to demonstrate:
|
||||
|
||||
```jsx
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
|
||||
function App() {
|
||||
const [inputValue, setInputValue] = useState("");
|
||||
const previousInputValue = useRef("");
|
||||
|
||||
useEffect(() => {
|
||||
previousInputValue.current = inputValue;
|
||||
}, [inputValue]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<input
|
||||
type="text"
|
||||
value={inputValue}
|
||||
onChange={(e) => setInputValue(e.target.value)}
|
||||
/>
|
||||
<h2>Current Value: {inputValue}</h2>
|
||||
<h2>Previous Value: {previousInputValue.current}</h2>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(<App />);
|
||||
|
||||
/*
|
||||
Start typing in the input field and you will
|
||||
see the current- and previous value.
|
||||
*/
|
||||
```
|
||||
|
||||

|
||||
|
||||
- Alternative of innerHTML in react
|
||||
|
||||
[https://stackoverflow.com/questions/19266197/reactjs-convert-html-string-to-jsx](https://stackoverflow.com/questions/19266197/reactjs-convert-html-string-to-jsx)
|
||||
|
||||
```jsx
|
||||
import ReactHtmlParser from 'react-html-parser'
|
||||
|
||||
<div>{ReactHtmlParser(htmlString)}</div>
|
||||
```
|
||||
|
||||
- Preventing propagation of event from parent to child
|
||||
|
||||
[https://www.antimath.info/jquery/prevent-inner-elements-trigger-an-event-on-the-parent/](https://www.antimath.info/jquery/prevent-inner-elements-trigger-an-event-on-the-parent/)
|
||||
|
||||
```jsx
|
||||
$('#parent a').on('click', function(event){
|
||||
//stop the event bubbling up to the parent
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
$('#parent').on('click', function(event){
|
||||
//attach event on the parent
|
||||
alert('Parent element clicked!');
|
||||
});
|
||||
```
|
||||
|
||||
- Disabling eslint for specific piece of code
|
||||
|
||||
```jsx
|
||||
searchednotes.push(note);
|
||||
}
|
||||
|
||||
setIsSearching(true);
|
||||
setSearchedNotes(searchednotes);
|
||||
}, [searchValue]); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
```
|
||||
|
||||
- React helmet
|
||||
|
||||
|
||||
|
||||
- Creating and export/import text file in react
|
||||
|
||||
|
||||
```jsx
|
||||
const download=()=>{
|
||||
fetch(`${HOST}`,{
|
||||
|
||||
})
|
||||
.then(res=>res.blob())
|
||||
.then(blob=>{
|
||||
const url = URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
link.download = "extraordinary12.mp3";
|
||||
link.href = url;
|
||||
link.click();
|
||||
})
|
||||
.catch(console.log)
|
||||
}
|
||||
```
|
||||
|
||||
[https://spin.atomicobject.com/2022/03/09/create-export-react-frontend/](https://spin.atomicobject.com/2022/03/09/create-export-react-frontend/)
|
||||
|
||||
[https://spin.atomicobject.com/2022/03/09/create-export-react-frontend/](https://spin.atomicobject.com/2022/03/09/create-export-react-frontend/)
|
||||
|
||||
[https://www.geeksforgeeks.org/how-to-read-a-local-text-file-using-javascript/](https://www.geeksforgeeks.org/how-to-read-a-local-text-file-using-javascript/)
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Read Text File</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<input type="file" name="inputfile"
|
||||
id="inputfile">
|
||||
<br>
|
||||
|
||||
<pre id="output"></pre>
|
||||
|
||||
<script type="text/javascript">
|
||||
document.getElementById('inputfile')
|
||||
.addEventListener('change', function() {
|
||||
|
||||
var fr=new FileReader();
|
||||
fr.onload=function(){
|
||||
document.getElementById('output')
|
||||
.textContent=fr.result;
|
||||
}
|
||||
|
||||
fr.readAsText(this.files[0]);
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||
- Common mistakes
|
||||
|
||||
[https://www.youtube.com/watch?v=Fhu5cu864ag](https://www.youtube.com/watch?v=Fhu5cu864ag)
|
||||
|
||||
[https://www.youtube.com/watch?v=Fhu5cu864ag](https://www.youtube.com/watch?v=Fhu5cu864ag)
|
||||
|
||||
|
||||
- image to dataURI
|
||||
|
||||
[Extract data uri from image](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/React%205b9af27e2c194a4cb22a32306e53c39f/Extract%20data%20uri%20from%20image%205610c5f6df1b49978b3a19.md)
|
||||
|
||||
- Nodejs 17+ changes
|
||||
|
||||
We need to add this in scripts section in package.json file:
|
||||
|
||||
```json
|
||||
"start": "react-scripts --openssl-legacy-provider start",
|
||||
"build": "react-scripts --openssl-legacy-provider build",
|
||||
```
|
||||
|
||||
the `--openssl-legacy-provider` flag is added as extra
|
||||
|
||||
- JoTai global state
|
||||
|
||||
Instead of using useState and passing it in prop repeatedly, we can use it globally by calling the state from a file.
|
||||
|
||||
atom.js
|
||||
|
||||
```jsx
|
||||
import { atom } from 'jotai'
|
||||
|
||||
export const countAtom = atom(0)
|
||||
|
||||
```
|
||||
|
||||
App.js
|
||||
|
||||
```jsx
|
||||
import { useAtom } from 'jotai'
|
||||
import {countAtom} from './atom'
|
||||
|
||||
function Counter() {
|
||||
const [count, setCount] = useAtom(countAtom)
|
||||
return (
|
||||
<h1>
|
||||
{count}
|
||||
<button onClick={() => setCount((c) => c + 1)}>one up</button>
|
||||
...
|
||||
```
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
# Creating react app to exe file
|
||||
|
||||
[https://medium.com/@duytq94/bundling-your-react-web-to-a-desktop-app-with-electron-1b19ebcf8933](https://medium.com/@duytq94/bundling-your-react-web-to-a-desktop-app-with-electron-1b19ebcf8933)
|
||||
|
||||
[https://stackoverflow.com/questions/57531216/can-i-create-a-windows-exe-from-a-react-project](https://stackoverflow.com/questions/57531216/can-i-create-a-windows-exe-from-a-react-project)
|
||||
|
||||
[https://livebook.manning.com/book/cross-platform-desktop-applications/chapter-7/25](https://livebook.manning.com/book/cross-platform-desktop-applications/chapter-7/25)
|
||||
|
||||
In a react project
|
||||
|
||||
`npm i electron-is-dev`
|
||||
|
||||
*electron-is-dev* let you know which environment is running.
|
||||
|
||||
**Second**, run this command to install these packages at devDependencies
|
||||
|
||||
```bash
|
||||
npm i -D concurrently electron electron-builder wait-on cross-env
|
||||
```
|
||||
|
||||
*concurrently* and *wait-on*: force waiting until server started then open Electron window.
|
||||
|
||||
*electron-builder:* distributing Electron app.
|
||||
|
||||
Add these
|
||||
|
||||
```json
|
||||
"name": "chat-desktop-app-demo",
|
||||
"version": "1.0.0",
|
||||
"author": "duytq94",
|
||||
"description": "Chat web app",
|
||||
"main": "public/electron.js",
|
||||
"homepage": "./",
|
||||
```
|
||||
|
||||
and this too
|
||||
|
||||
```json
|
||||
"build": {
|
||||
"appId": "com.loyno-mathcs.harsh.weatherstation.wotdevice",
|
||||
"files": [
|
||||
"build/**/*",
|
||||
"node_modules/**/*"
|
||||
],
|
||||
"win": {
|
||||
"icon": "./public/icon.png"
|
||||
},
|
||||
"directories": {
|
||||
"buildResources": "assets"
|
||||
}
|
||||
},
|
||||
```
|
||||
|
||||
Also add these under scripts:
|
||||
|
||||
```json
|
||||
"electron-dev": "concurrently \"cross-env BROWSER=none npm start\" \"wait-on http://localhost:3000 && electron .\"",
|
||||
"electron-pack": "electron-builder -c.extraMetadata.main=build/electron.js",
|
||||
"preelectron-pack": "react-scripts build"
|
||||
```
|
||||
|
||||
**3. Config Electron**
|
||||
|
||||
Create a file name *electron.js* and put into *public* folder
|
||||
|
||||
```jsx
|
||||
const electron = require('electron');
|
||||
const { app, BrowserWindow } = electron;
|
||||
const path = require('path');
|
||||
const isDev = require('electron-is-dev');
|
||||
|
||||
let mainWindow = null;
|
||||
app.on('ready', createWindow);
|
||||
app.on('window-all-closed', function () {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
});
|
||||
app.on('activate', function () {
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
});
|
||||
function createWindow() {
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
title: "Chat desktop app demo"
|
||||
});
|
||||
mainWindow.loadURL(isDev ? 'http://localhost:3000' : `file://${path.join(__dirname, '../build/index.html')}`);
|
||||
mainWindow.on('closed', function () {
|
||||
mainWindow = null
|
||||
})
|
||||
mainWindow.on('page-title-updated', function (e) {
|
||||
e.preventDefault()
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
In development mode, the code quite simple, it creates a window and load the content from *[http://localhost:3000*.](http://localhost:3000./) That’s it.
|
||||
|
||||
title will be same as in title tag
|
||||
|
||||
name of app is configured with value of name key in package.json.
|
||||
|
||||
for configuring icon in development mode
|
||||
|
||||
```jsx
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
title: "Chat desktop app demo", //to override title tag
|
||||
icon: './public/icon.ico',
|
||||
});
|
||||
```
|
||||
|
||||
For icon in production mode(exe form)
|
||||
|
||||
add this under build
|
||||
|
||||
```json
|
||||
"win": {
|
||||
"icon": "./public/icon.png"
|
||||
},
|
||||
```
|
||||
|
||||
and this icon must be greater or equal to 256x256.
|
||||
|
||||
For adding menu when right clicked
|
||||
|
||||
[https://www.npmjs.com/package/electron-context-menu](https://www.npmjs.com/package/electron-context-menu)
|
||||
|
||||
use old version like this old
|
||||
`npm i electron-context-menu@3.4.0`
|
||||
```jsx
|
||||
const contextMenu = require("electron-context-menu");
|
||||
|
||||
contextMenu({
|
||||
showSaveImageAs: true,
|
||||
});
|
||||
```
|
||||
|
||||
- Tauri
|
||||
|
||||
[https://www.youtube.com/watch?v=l4Dy5m3MnWk](https://www.youtube.com/watch?v=l4Dy5m3MnWk)
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
# Extract data uri from image
|
||||
|
||||
[https://mitch.codes/how-to-get-the-data-url-of-an-image-in-javascript/](https://mitch.codes/how-to-get-the-data-url-of-an-image-in-javascript/)
|
||||
|
||||
Normally we have to use callback function for image.onload just like in below image
|
||||
|
||||
```jsx
|
||||
const avatarImg=new Image()
|
||||
avatarImg.src=source // src of img
|
||||
avatarImg.onload = function() {
|
||||
var c = document.getElementById("myCanvas");
|
||||
var ctx = c.getContext("2d");
|
||||
ctx.canvas.width = avatarImg.width;
|
||||
ctx.canvas.height = avatarImg.height;
|
||||
|
||||
ctx.drawImage(avatarImg, 0, 0);
|
||||
};
|
||||
```
|
||||
|
||||
this is callback function
|
||||
|
||||
```jsx
|
||||
function getBase64Image(img) {
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.width = img.width;
|
||||
canvas.height = img.height;
|
||||
var ctx = canvas.getContext("2d");
|
||||
ctx.drawImage(img, 0, 0);
|
||||
var dataURL = canvas.toDataURL("image/png");
|
||||
return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
|
||||
}
|
||||
|
||||
var base64 = getBase64Image(document.getElementById("imageid"));
|
||||
```
|
||||
|
||||
Using promises we can convert to async await to make it look like synchronous thus easier to use and debug.
|
||||
|
||||
```jsx
|
||||
const createImage = (src) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const image = new Image();
|
||||
image.crossOrigin = "anonymous";
|
||||
image.src = src;
|
||||
|
||||
image.onload = () => {
|
||||
resolve(image);
|
||||
};
|
||||
|
||||
image.onerror = (e) => {
|
||||
reject(e);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const getDataURL=async (src) => {
|
||||
|
||||
const image = await createImage(src);
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = image.width;
|
||||
|
||||
canvas.height = image.height;
|
||||
|
||||
const ctx = canvas.getContext("2d");
|
||||
ctx.drawImage(image, 0, 0);
|
||||
const dataURL = canvas.toDataURL("image/png");
|
||||
return dataURL
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Whole code to convert image http url and local file to data uri(base 64 encoded):
|
||||
|
||||
[Full codebase for conversion to data uri](../../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/React%205b9af27e2c194a4cb22a32306e53c39f/Extract%20data%20uri%20from%20image%205610c5f6df1b49978b3a19/Full%20codebase%20for%20conversion%20to%20data%20uri%20ea49e40ac.md)
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
# Full codebase for conversion to data uri
|
||||
|
||||
JSX:
|
||||
|
||||
```jsx
|
||||
const App = () => {
|
||||
const [src, setSrc] = useState("");
|
||||
const [uri, setUri] = useState("");
|
||||
|
||||
const createImage = () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const image = new Image();
|
||||
image.crossOrigin = "anonymous";
|
||||
image.src = src;
|
||||
|
||||
image.onload = () => {
|
||||
resolve(image);
|
||||
};
|
||||
|
||||
image.onerror = (e) => {
|
||||
reject(e);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(async () => {
|
||||
// const image = new Image();
|
||||
// image.crossOrigin = "anonymous";
|
||||
// image.src = src;
|
||||
|
||||
// image.onload = () => {
|
||||
const image = await createImage();
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = image.width;
|
||||
|
||||
canvas.height = image.height;
|
||||
|
||||
const ctx = canvas.getContext("2d");
|
||||
ctx.drawImage(image, 0, 0);
|
||||
const dataURL = canvas.toDataURL("image/png");
|
||||
setUri(dataURL);
|
||||
// console.log(dataURL);
|
||||
// };
|
||||
}, [src]);
|
||||
|
||||
const handleChange = (e) => {
|
||||
setSrc(e.target.value);
|
||||
};
|
||||
|
||||
const copyToClipboard = () => {
|
||||
navigator.clipboard.writeText(uri).then(
|
||||
function () {
|
||||
console.log("Async: Copying to clipboard was successful!");
|
||||
},
|
||||
function (err) {
|
||||
console.error("Async: Could not copy text: ", err);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const uploadImage = () => {
|
||||
const fileElement = document.createElement("input");
|
||||
fileElement.setAttribute("type", "file");
|
||||
fileElement.setAttribute("accept", "image/*");
|
||||
fileElement.click();
|
||||
|
||||
fileElement.onchange = (e) => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(fileElement.files[0]);
|
||||
|
||||
reader.onload = () => {
|
||||
setSrc(reader.result);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="mainSection">
|
||||
<div className="inputs">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Insert the url of image"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<div className="or">OR</div>
|
||||
<div className="uploadImageSection">
|
||||
<button className="uploadImage" onClick={uploadImage}>
|
||||
Upload Image
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
<div className="base64Section">
|
||||
<div className="base64URI">{uri.substr(0, 100)}</div>
|
||||
<button
|
||||
onClick={copyToClipboard}
|
||||
title="Copy data URI"
|
||||
className="copyToClipboard"
|
||||
>
|
||||
<i class="fa fa-copy"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{src ? <img src={src} alt="image" /> : ""}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
CSS:
|
||||
|
||||
```css
|
||||
.mainSection {
|
||||
margin: auto;
|
||||
margin-top: 3rem;
|
||||
width: fit-content;
|
||||
}
|
||||
|
||||
.mainSection input[type="text"] {
|
||||
height: 1.5rem;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.mainSection .inputs {
|
||||
width: fit-content;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.mainSection .or {
|
||||
text-align: center;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.mainSection .uploadImageSection {
|
||||
margin-top: 1rem;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.mainSection .uploadImage {
|
||||
cursor: pointer;
|
||||
padding: 0.5rem;
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.mainSection .base64Section {
|
||||
margin: 1rem auto;
|
||||
padding: 0.5rem;
|
||||
display: flex;
|
||||
width: fit-content;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.base64Section button {
|
||||
cursor: pointer;
|
||||
background-color: white;
|
||||
border: none;
|
||||
border: 1px solid black;
|
||||
height: fit-content;
|
||||
padding: 0.5rem;
|
||||
font-size: 1.2rem;
|
||||
transition: all 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
.base64Section button:hover {
|
||||
background-color: rgb(100, 100, 100, 0.3);
|
||||
}
|
||||
|
||||
.mainSection .base64URI {
|
||||
height: 3rem;
|
||||
border: 1px solid black;
|
||||
width: 200px;
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
/* max-width: 400px; */
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
.mainSection img {
|
||||
margin-top: 1rem;
|
||||
max-height: 200px;
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
# Links
|
||||
|
||||
- Localstorage
|
||||
|
||||
[https://hacks.mozilla.org/2012/02/saving-images-and-files-in-localstorage/](https://hacks.mozilla.org/2012/02/saving-images-and-files-in-localstorage/)
|
||||
|
||||
- Low size node modules for react
|
||||
|
||||
[https://github.com/nafeu/slim-react-starter](https://github.com/nafeu/slim-react-starter)
|
||||
|
||||
[https://liaogg.medium.com/build-your-next-react-app-with-vite-part-2-6d51b58561c8](https://liaogg.medium.com/build-your-next-react-app-with-vite-part-2-6d51b58561c8)
|
||||
|
||||
`npm create vite@latest ./`
|
||||
|
||||
`npm i`
|
||||
|
||||
`npm run dev`
|
||||
|
||||
[slim-react-starter-main.zip](../../../_resources/slim-react-starter-main.zip)
|
||||
|
||||
- Convert callback to async/await
|
||||
|
||||
[https://www.coreycleary.me/how-to-rewrite-a-callback-function-in-promise-form-and-async-await-form-in-javascript/](https://www.coreycleary.me/how-to-rewrite-a-callback-function-in-promise-form-and-async-await-form-in-javascript/)
|
||||
|
||||
- IndexDB
|
||||
|
||||
[https://levelup.gitconnected.com/using-the-indexeddb-api-with-react-and-hooks-4e63d83a5d1b](https://levelup.gitconnected.com/using-the-indexeddb-api-with-react-and-hooks-4e63d83a5d1b)
|
||||
|
||||
- Chat app
|
||||
|
||||
[https://www.youtube.com/watch?v=k4mjF4sPITE](https://www.youtube.com/watch?v=k4mjF4sPITE)
|
||||
|
||||
- context to pass props
|
||||
|
||||
[https://reactjs.org/docs/context.html](https://reactjs.org/docs/context.html)
|
||||
|
||||
- imp libraries
|
||||
|
||||
[https://javascript.plainenglish.io/16-libraries-you-should-know-as-a-react-developer-c9c595c8d25e](https://javascript.plainenglish.io/16-libraries-you-should-know-as-a-react-developer-c9c595c8d25e)
|
||||
|
||||
X
|
||||
|
||||
- bypass cors
|
||||
|
||||
[https://www.npmjs.com/package/cors-anywhere](https://www.npmjs.com/package/cors-anywhere)
|
||||
|
||||
reactjs proxy: [https://www.youtube.com/watch?v=N4yUiQiTvwU](https://www.youtube.com/watch?v=N4yUiQiTvwU)
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
# React app to mobile app
|
||||
|
||||
- React app to mobile app
|
||||
|
||||
[https://medium.com/@pshubham/using-react-with-cordova-f235de698cc3](https://medium.com/@pshubham/using-react-with-cordova-f235de698cc3)
|
||||
|
||||
`npm i -g cordova@9.0.0`
|
||||
|
||||
`cordova create playlist [com.playlist.app](http://com.playlist.app) Playlist`
|
||||
|
||||
where playlist is app name
|
||||
|
||||
public and src folder to be copied
|
||||
|
||||
copy browserslist, scripts and dependencies to package.json.
|
||||
|
||||
also add `"homepage": "./",` in **package.json**.
|
||||
|
||||
Add
|
||||
|
||||
```html
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; media-src *; img-src 'self' data: content:;">
|
||||
<meta name="format-detection" content="telephone=no">
|
||||
<meta name="msapplication-tap-highlight" content="no">
|
||||
<meta name="viewport" content="initial-scale=1, width=device-width, viewport-fit=cover">
|
||||
|
||||
```
|
||||
|
||||
under head tag in **public/index.html**.
|
||||
|
||||
Add `<script src="cordova.js" type="text/javascript"></script>` at end under body tag.
|
||||
|
||||
Adding even listener when cordava is used and device is ready.
|
||||
|
||||
```jsx
|
||||
const renderReactDom = () => {
|
||||
ReactDOM.render(<App />, document.getElementById('root'));
|
||||
};
|
||||
|
||||
if (window.cordova) {
|
||||
document.addEventListener('deviceready', () => {
|
||||
renderReactDom();
|
||||
}, false);
|
||||
} else {
|
||||
renderReactDom();
|
||||
}
|
||||
```
|
||||
|
||||
in src/index.js.
|
||||
|
||||
In this file we need to perform two main functions:
|
||||
|
||||
- Execute the react build process
|
||||
- React-scripts generates the build output to the **build/** folder and cordova uses **www/** as its input directory. So once the react build is completed we need to rename **build/** to **www/**
|
||||
|
||||
[https://www.youtube.com/watch?v=9OnZuuJJlCk](https://www.youtube.com/watch?v=9OnZuuJJlCk)
|
||||
|
||||
To square the icons for android apps:
|
||||
|
||||
[https://squaremyimage.com/](https://squaremyimage.com/)
|
||||
|
||||
To get different icons resizes like app-icon, playstore icon etc, use:
|
||||
|
||||
[https://resizeappicon.com/](https://resizeappicon.com/)
|
||||
|
||||
```bash
|
||||
cordova platform add android
|
||||
cordova build android
|
||||
```
|
||||
|
||||
For release build use:
|
||||
|
||||
`cordova build —release android`
|
||||
|
||||
[Cordova Website To App Conversion new.pdf](../../../_resources/Cordova_Website_To_App_Conversion_new.pdf)
|
||||
|
||||
- html5 input file issue
|
||||
|
||||
[https://pragmaapps.com/fix-html5-file-input-cordova-android/](https://pragmaapps.com/fix-html5-file-input-cordova-android/)
|
||||
|
||||
[https://github.com/apache/cordova-plugin-inappbrowser/](https://github.com/apache/cordova-plugin-inappbrowser/)
|
||||
|
||||
[https://cordova.apache.org/docs/en/10.x/reference/cordova-plugin-file/#sample](https://cordova.apache.org/docs/en/10.x/reference/cordova-plugin-file/#sample)
|
||||
|
||||
[Dealing with Android content URIs in a Cordova based project](https://engineering.spideroak.com/how-to-deal-with-the-android-filesystem-in-a-cordova-based-project/)
|
||||
|
||||
[https://engineering.spideroak.com/how-to-deal-with-the-android-filesystem-in-a-cordova-based-project/](https://engineering.spideroak.com/how-to-deal-with-the-android-filesystem-in-a-cordova-based-project/)
|
||||
|
||||
[https://stackoverflow.com/questions/35056472/how-to-create-a-separate-directory-for-cordova-app-and-storing-data-in-it](https://stackoverflow.com/questions/35056472/how-to-create-a-separate-directory-for-cordova-app-and-storing-data-in-it)
|
||||
|
||||
|
||||
[https://www.andreszsogon.com/using-android-8-and-9-emulators-without-android-studio/](https://www.andreszsogon.com/using-android-8-and-9-emulators-without-android-studio/)
|
||||
|
||||
[https://doc.xuwenliang.com/docs/cordova/1630](https://doc.xuwenliang.com/docs/cordova/1630)
|
||||
|
||||
- Debugging mobile app of cordova
|
||||
|
||||
[https://geeklearning.io/apache-cordova-and-remote-debugging-on-android/](https://geeklearning.io/apache-cordova-and-remote-debugging-on-android/)
|
||||
|
||||
Type `chrome://inspect` in browser address bar.
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
# SQL
|
||||
|
||||
- **Importing and exporting mysql dump file**
|
||||
1. To import:
|
||||
|
||||
```bash
|
||||
mysql -u username -p database_name < file.sql
|
||||
```
|
||||
|
||||
1. To export:
|
||||
`mysqldump -u root -p hospitals > C:\Users\harsh\Downloads\Documents\hospitals.sql`
|
||||
2. to export only schema
|
||||
|
||||
- Postgresql
|
||||
|
||||
to load postgresql database
|
||||
|
||||
```bash
|
||||
psql -U postgres smart-brain
|
||||
```
|
||||
|
||||
Here postgres is owner name and smart-brain is name of data base. It will prompt for password which is U2FsdGVkX1/k+uOTLs4gSYVmxYAJEQybNVGnxIQVHyg=. Refer to
|
||||
|
||||
[Web development](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/Web%20development%2083dd4e6675f04ba782a6865a434a0598.md)
|
||||
|
||||
for decrypting it.
|
||||
|
||||
To load postgresql without database:
|
||||
|
||||
`psql -U postgres`
|
||||
|
||||
To create database:
|
||||
|
||||
`createdb mydb -U postgres`
|
||||
|
||||
or
|
||||
|
||||
```bash
|
||||
psql -U postgres
|
||||
create database mydb;
|
||||
```
|
||||
|
||||
To get list of database:
|
||||
|
||||
`\l`
|
||||
|
||||
To connect to database when login as user
|
||||
|
||||
`\connect dbname`
|
||||
|
||||
`\q`: To quit
|
||||
- List tables, views and sequences
|
||||
`\d`
|
||||
- Describe tables
|
||||
`\d <table_name>`
|
||||
|
||||
- MYSQL
|
||||
|
||||
Online compiler: [https://www.mycompiler.io/new/sql](https://www.mycompiler.io/new/sql)
|
||||
|
||||
To load mysql shell in command prompt:
|
||||
|
||||
`mysql -u root -p`
|
||||
|
||||
Here root is owner_name. This will prompt for password which is ‘password’.
|
||||
|
||||
To get list of database:
|
||||
|
||||
`show databases;`
|
||||
|
||||
To create database
|
||||
```sql
|
||||
drop database if exists database_name;
|
||||
create database database_name;
|
||||
```
|
||||
|
||||
To load database
|
||||
|
||||
`use hospitals;`
|
||||
|
||||
hospitals here is name of database
|
||||
|
||||
Once database is loaded, to get list of tables:
|
||||
|
||||
`show tables;`
|
||||
|
||||
To get schema of tables:
|
||||
|
||||
`desc patients;` or `describe patients;`
|
||||
|
||||
where patients is name of table
|
||||
|
||||
- Creating table
|
||||
|
||||
```sql
|
||||
create table project (
|
||||
emp_id int not null,
|
||||
id int not null,
|
||||
name varchar(30),
|
||||
location varchar(40),
|
||||
primary key(emp_id)
|
||||
);
|
||||
```
|
||||
- Adding Auto increment
|
||||
|
||||
```sql
|
||||
-- To let the AUTO_INCREMENT sequence start with another value, use the following SQL statement:
|
||||
ALTER TABLE Persons AUTO_INCREMENT=100;
|
||||
|
||||
alter table employee
|
||||
modify emp_id int not null auto_increment;
|
||||
```
|
||||
|
||||
- Constraints
|
||||
|
||||
[How to use ADD CONSTRAINT in SQL (with examples) (cockroachlabs.com)](https://www.cockroachlabs.com/blog/sql-add-constraint/)
|
||||
|
||||
- LIKE
|
||||
|
||||
[SQL LIKE Operator (w3schools.com)](https://www.w3schools.com/SQL/sql_like.asp)
|
||||
|
||||
SELECT *column1, column2, ...* FROM *table_name* WHERE *columnN* LIKE *pattern*;
|
||||
|
||||
**Tip:** You can also combine any number of conditions using `AND` or `OR` operators.
|
||||
|
||||
Here are some examples showing different `LIKE` operators with '%' and '_' wildcards:
|
||||
|
||||
| LIKE Operator | Description |
|
||||
| --- | --- |
|
||||
| WHERE CustomerName LIKE 'a%' | Finds any values that start with "a" |
|
||||
| WHERE CustomerName LIKE '%a' | Finds any values that end with "a" |
|
||||
| WHERE CustomerName LIKE '%or%' | Finds any values that have "or" in any position |
|
||||
| WHERE CustomerName LIKE '_r%' | Finds any values that have "r" in the second position |
|
||||
| WHERE CustomerName LIKE 'a_%' | Finds any values that start with "a" and are at least 2 characters in length |
|
||||
| WHERE CustomerName LIKE 'a__%' | Finds any values that start with "a" and are at least 3 characters in length |
|
||||
| WHERE ContactName LIKE 'a%o' | Finds any values that start with "a" and ends with "o" |
|
||||
- JOIN
|
||||
|
||||
```sql
|
||||
create table Member (
|
||||
'Member ID' int not null,
|
||||
'First Name' varchar(50),
|
||||
'Last Name' varchar(50),
|
||||
gender varchar(10),
|
||||
age int not null,
|
||||
country varchar(50),
|
||||
joined_date date,
|
||||
primary key('Member ID')
|
||||
);
|
||||
|
||||
create table Booking (
|
||||
BookingID int not null,
|
||||
Room varchar(50),
|
||||
|
||||
Days int,
|
||||
cost per day float,
|
||||
status varchar(30),
|
||||
primary key(BookingID)
|
||||
);
|
||||
|
||||
create table Make (
|
||||
Date date,
|
||||
MemberID int not null,
|
||||
BookingID int not null
|
||||
);
|
||||
|
||||
-- Main ............
|
||||
SELECT 'First Name', 'Last Name', Age, 'Date'
|
||||
FROM Member as me JOIN Make as ma JOIN Booking as b
|
||||
ON me.'Member ID'=ma.'MemberID' and ma.BookingID=b.BookingID;
|
||||
```
|
||||
|
||||
- Insert into
|
||||
|
||||
```sql
|
||||
INSERT INTO table_name (column1, column2, column3, ...)
|
||||
VALUES (value1, value2, value3, ...);
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```sql
|
||||
INSERT INTO table_name
|
||||
VALUES (value1, value2, value3, ...);
|
||||
```
|
||||
|
||||
For multiple rows
|
||||
|
||||
```sql
|
||||
INSERT INTO CUSTOMERS (ID,NAME,AGE,ADDRESS,SALARY)
|
||||
VALUES (4, 'Chaitali', 25, 'Mumbai', 6500.00 ), (5, 'Hardik', 27, 'Bhopal', 8500.00 ), (6, 'Komal', 22, 'MP', 4500.00 );
|
||||
```
|
||||
|
||||
- Delete records
|
||||
```sql
|
||||
-- to delete all records
|
||||
delete from table_name;
|
||||
|
||||
-- to delete record id=5
|
||||
delete from table_name
|
||||
where id=5;
|
||||
|
||||
```
|
||||
- Date
|
||||
|
||||
```sql
|
||||
create table Member (
|
||||
...
|
||||
.....
|
||||
joined_date date,
|
||||
|
||||
);
|
||||
|
||||
insert into Member
|
||||
values(1582,'Mara','Hash','Female',25,'Uganda','2020-08-16'), (3549,'Kathleen','Hanner','Female',25,'United States','2017-12-12');
|
||||
|
||||
```
|
||||
|
||||
|
||||
If there column name contain spaces then enclose them with ticks → `MEMBER ID`
|
||||
|
||||
- Handwritten
|
||||
|
||||
[sql.pdf](../../_resources/sql.pdf)
|
||||
|
||||
[sql.pdf](../../_resources/sql%201.pdf)
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
# Spring
|
||||
|
||||
https://www.youtube.com/watch?v=QuvS_VLbGko : crash course of 1hr
|
||||
|
||||
https://www.youtube.com/watch?v=Ch163VfHtvA&list=PLsyeobzWxl7oA8QOlMtQsRT_I7Rx2hoX4 : telusko playlist
|
||||
|
||||

|
||||
|
||||
### EJB (Enterprise java bean)
|
||||
- Three types of EJB
|
||||
1. Session bean : Contains business logic that is invoked by local, remote or web service client
|
||||
2. Message driven bean : Contains business logic that is invoked by passing message
|
||||
3. Entity bean : Encapsulates state that can be persisted in database. it is deprecated and replaced by java persistent API
|
||||
|
||||
|
||||
POJO : Plain Old Java Object . Ordinary object which is not bound by special restriction. https://www.javatpoint.com/pojo-in-java
|
||||
|
||||
|
||||
Interface : multiple inheritance feature in java
|
||||
annotations : Java Annotation is a tag that represents the metadata i.e. attached with class, interface, methods or fields to indicate some additional information which can be used by java compiler and JVM.
|
||||
eg: `@Override`, `@Deprecated`
|
||||
|
||||
|
||||
**Spring**
|
||||
An open source framework to build enterprise java applications on any deployment platform. It is a collection of subfraneworks called layers such as Spring AOP. Spring Object-Relational Mapping (Spring ORM). Spring Web Flow, and Spring Web MVC.
|
||||
Spring can integrate with other frameworks like hibernate and struts.
|
||||
|
||||
**Spring boot**
|
||||
We need to work on configuration thouroughly instead of coding itself. Spring boot solves this issue as spring boot comes with built in configurations and dependencies so developers can focus on conventions. We can add additional configurations too on top of basic ones.
|
||||
Spring boot provides us with embedded server/tomcat so instead of needing a separate server, JVM is enough. So JAR file will have embedded tomcat.
|
||||
There is no XML file so we can add properties in `application.properties`
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
# Web development
|
||||
|
||||
- Encrypt/decrypt:
|
||||
|
||||
|
||||
|
||||
|
||||
[https://github.com/Marcello09/notion-lock](https://github.com/Marcello09/notion-lock)
|
||||
https://marcello09.github.io/notion-lock/en
|
||||
[notion-lock-main.zip](../../_resources/notion-lock-main.zip)
|
||||
|
||||
[https://www.geeksforgeeks.org/encrypt-and-decrypt-image-using-python/](https://www.geeksforgeeks.org/encrypt-and-decrypt-image-using-python/)
|
||||
|
||||
# Contents
|
||||
|
||||
[Basics](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/Basics%203c39793aa5424ea9a779c784f89998a7.md)
|
||||
|
||||
[SQL](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/SQL%204f218c66fb524cc1ba28ef7c5342e101.md)
|
||||
|
||||
[Javascript](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/Javascript%206f088d74b3964122989469823aade1d6.md)
|
||||
|
||||
[React](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/React%205b9af27e2c194a4cb22a32306e53c39f.md)
|
||||
|
||||
[Heroku](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/Heroku%20531d47e94b8843d7a0dc8ffce482bf9e.md)
|
||||
|
||||
[CSS](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/CSS%20cf8824c7de95492bab938154abcc0bfc.md)
|
||||
|
||||
[GitHub](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/GitHub%20cc67e8c9e0c945a587b473d533a8d80a.md)
|
||||
|
||||
[NodeJS](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/NodeJS%206d499253059041d699e2e6fa36ded013.md)
|
||||
|
||||
[Extras](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/Extras%2052e0285b6a994018ba3a68c7c33ca3de.md)
|
||||
|
||||
- Courses
|
||||
|
||||
[FreeCourseSite.com-Udemy - The Complete Web Developer in 2021 Zero to Mastery.torrent](../../_resources/FreeCourseSite.com-Udemy_-_The_Complete_Web_Develo.torrent)
|
||||
|
||||
|
||||
[FreeCourseSite.com-Udemy - The Complete Web Developer in 2023 Zero to Mastery.torrent](../../_resources/FreeCourseSite.com-Udemy%20-%20The%20Complete%20Web%20Develo.torrent)
|
||||
|
||||
|
||||
|
||||
|
||||
[Linux](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/Linux%20365066f42694404fbedd4a9c7df5cbab.md)
|
||||
|
||||
[Windows](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/Windows%2058c7505ead1041aeb22a40048b7b761c.md)
|
||||
|
||||
[Spring ](../../Export-9fad9947-5bd5-4195-952b-6512c5a4beb1/Web%20development%2083dd4e6675f04ba782a6865a434a0598/Spring%209cf44203d0aa46878556b8b5f725cd6a.md)
|
||||
|
||||
|
||||
|
||||
**Handwritten Notes**
|
||||
1. Web Development Basics
|
||||
[web_dev_basics.pdf](../../_resources/web_dev_basics.pdf)
|
||||
2. HTML
|
||||
[html.pdf](../../_resources/html.pdf)
|
||||
3. CSS
|
||||
[css.pdf](../../_resources/css.pdf)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
# Windows
|
||||
|
||||
- For removing feedback hub
|
||||
|
||||
[https://www.youtube.com/watch?v=W5L4oxS6HpE](https://www.youtube.com/watch?v=W5L4oxS6HpE)
|
||||
|
||||
- Making windows flexible
|
||||
|
||||
[https://www.itechtics.com/easily-enable-group-policy-editor-gpedit-msc-in-windows-10-home-edition/](https://www.itechtics.com/easily-enable-group-policy-editor-gpedit-msc-in-windows-10-home-edition/) : to enable gpedit to control aspects without making changes in registry directly
|
||||
|
||||
[add_gpedit_msc_by_drudger_d3kh6vm.zip](../../_resources/add_gpedit_msc_by_drudger_d3kh6vm.zip)
|
||||
|
||||
Also use this to install gpedit in windows 10 home
|
||||
|
||||
also following bat file can be executed:
|
||||
|
||||
[gpedit-enabler.bat](../../_resources/gpedit-enabler.bat)
|
||||
|
||||
- Disabling compatibility telemetry
|
||||
|
||||
[https://www.youtube.com/watch?v=59dhIfCWPyA](https://www.youtube.com/watch?v=59dhIfCWPyA)
|
||||
|
||||
Command to open task scheduler on Run: `taskschd.msc`.
|
||||
|
||||
- Windows on virtual machine
|
||||
|
||||
[https://www.youtube.com/watch?v=JT8EXoobjSc](https://www.youtube.com/watch?v=JT8EXoobjSc)
|
||||
|
||||
For resizing : [https://www.ghacks.net/2022/06/11/how-to-change-the-windows-screen-size-in-virtualbox/](https://www.ghacks.net/2022/06/11/how-to-change-the-windows-screen-size-in-virtualbox/)
|
||||
|
||||
- Commands
|
||||
|
||||
For disk cleanup: cleanmgr
|
||||
For group policy editor: gpedit.msc
|
||||
|
||||
- To enable windows sandbox in windows 19 home
|
||||
|
||||
[https://www.tenforums.com/tutorials/131437-enable-windows-sandbox-feature-windows-10-home-edition.html](https://www.tenforums.com/tutorials/131437-enable-windows-sandbox-feature-windows-10-home-edition.html)
|
||||
|
||||
- Disable startups
|
||||
|
||||
[Autoruns.zip](../../_resources/Autoruns.zip)
|
||||
|
||||
- copy folders with excluding subfolders
|
||||
|
||||
`robocopy SOURCE DEST /mir /xd node_modules`
|
||||
|
||||
- for loop
|
||||
|
||||
For the folder name and drive, you can use:
|
||||
|
||||
```
|
||||
echo %~dp0
|
||||
|
||||
```
|
||||
|
||||
You can get a lot more information using different modifiers:
|
||||
|
||||
```
|
||||
%~I - expands %I removing any surrounding quotes (")
|
||||
%~fI - expands %I to a fully qualified path name
|
||||
%~dI - expands %I to a drive letter only
|
||||
%~pI - expands %I to a path only
|
||||
%~nI - expands %I to a file name only
|
||||
%~xI - expands %I to a file extension only
|
||||
%~sI - expanded path contains short names only
|
||||
%~aI - expands %I to file attributes of file
|
||||
%~tI - expands %I to date/time of file
|
||||
%~zI - expands %I to size of file
|
||||
|
||||
The modifiers can be combined to get compound results:
|
||||
%~dpI - expands %I to a drive letter and path only
|
||||
%~nxI - expands %I to a file name and extension only
|
||||
%~fsI - expands %I to a full path name with short names only
|
||||
```
|
||||
|
||||
`for %I in (softwares/*) do dir %I`
|
||||
|
||||
This lists all the files (and only the files) in the current directory and its subdirectories recursively:
|
||||
|
||||
```
|
||||
for /r %i in (*) do echo %i
|
||||
|
||||
```
|
||||
|
||||
Also if you run that command in a batch file you need to double the % signs.
|
||||
|
||||
```
|
||||
for /r %%i in (*) do echo %%i
|
||||
```
|
||||
|
||||
[https://stackoverflow.com/questions/138497/iterate-all-files-in-a-directory-using-a-for-loop](https://stackoverflow.com/questions/138497/iterate-all-files-in-a-directory-using-a-for-loop)
|
||||
|
||||
|
||||
[https://superuser.com/questions/494959/how-to-delete-a-file-ending-in-a-dot-in-windows-7](https://superuser.com/questions/494959/how-to-delete-a-file-ending-in-a-dot-in-windows-7)
|
||||
|
||||
- Windows 11 cons
|
||||
|
||||
[https://www.youtube.com/watch?v=XsVbyGbSkds](https://www.youtube.com/watch?v=XsVbyGbSkds)
|
||||
|
||||
- Disabling enabling keys
|
||||
|
||||
Hi General_Townski, we are happy to advise you. Please follow the steps below.
|
||||
|
||||
1. Tap the Windows icon in the bottom left corner and type “cmd” in the search bar.
|
||||
2. Select “Run as administrator” under “Command Prompt.”
|
||||
3. Click “Yes” to confirm that you’re okay with the Command Prompt app making changes to your computer.
|
||||
4. Once the Command Prompt window opens, type the following command line, and then hit Enter: sc config i8042prt start= disabled
|
||||
5. Close the Command Prompt and ensure restart your laptop.
|
||||
|
||||
If you ever want to re-enable the keyboard in the future, you just need to run the Command Prompt app and enter the following command: sc config i8042prt start= auto
|
||||
|
||||
- Disable fast startup
|
||||
1. Navigate to the Control Panel and select 'Power Options. '
|
||||
2. Choose 'Choose what the power buttons do. '
|
||||
3. Click on 'Change settings that are currently unavailable. '
|
||||
4. Under 'Shutdown settings,' uncheck the 'Turn on fast startup' box.
|
||||
BIN
_resources/007b8f36b93ea47fc47ea9d9d839219c.png
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
_resources/04e385c71738cef51c4f0c30e5aa9413.png
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
_resources/0582a9e09684b83265f88c682b64d183.png
Normal file
|
After Width: | Height: | Size: 359 KiB |
BIN
_resources/08d8252515c656676d3981558cbed3eb.png
Normal file
|
After Width: | Height: | Size: 371 KiB |
BIN
_resources/097ea2e49a5653134efdf96520aeec4d.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
_resources/0a884ef560d394637c84d895100507f1.png
Normal file
|
After Width: | Height: | Size: 227 KiB |
BIN
_resources/0e4936b3f77b2a7a89326676fcd8c61d.png
Normal file
|
After Width: | Height: | Size: 487 KiB |
13153
_resources/10 Free Tailwind CSS UI Kits & Component Libraries.html
Normal file
BIN
_resources/125d3936b8ad863abf57a9a02664ed00.png
Normal file
|
After Width: | Height: | Size: 112 KiB |
BIN
_resources/163d5f38ffe0f64657b0d3a1312cfa5d.png
Normal file
|
After Width: | Height: | Size: 133 KiB |
BIN
_resources/1676a37516bad6609caceb44553e4ad9.png
Normal file
|
After Width: | Height: | Size: 147 KiB |
BIN
_resources/16f5148001e1c91c62a9aed090efbc81.png
Normal file
|
After Width: | Height: | Size: 293 KiB |
BIN
_resources/1a1f40be732033c0053fa83d873c51ea.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
_resources/1a819c18ab7dea9f21918c9abcfae274.png
Normal file
|
After Width: | Height: | Size: 184 KiB |
BIN
_resources/1b58f6f7bcd5f68fb6e365e7991f188a.png
Normal file
|
After Width: | Height: | Size: 191 KiB |
BIN
_resources/1d38fd0dab0a77e7ea13fbff323d6e9b.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
_resources/1e3b163f68f9febc422b23deca362263.png
Normal file
|
After Width: | Height: | Size: 570 KiB |
BIN
_resources/200c50e136baf363372e70d9b9296e32.png
Normal file
|
After Width: | Height: | Size: 47 KiB |
BIN
_resources/222ea4fd9e8c09d346f85017d5cd8c55.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
_resources/22e16ab2ee598c24e4799b0ef66d2f90.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
_resources/23e186dca9071ca2d6d89f0c12cc7d5f.png
Normal file
|
After Width: | Height: | Size: 333 KiB |
BIN
_resources/28c2b61713696f74be557f4c8da73a95.png
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
_resources/2aaa904c878003de6858431bb1a01404.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
_resources/2edcc32c60246452cda407c2da2e3c18.png
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
_resources/2ee849a00b2a8bf5f5b09d9c65a71bc4.png
Normal file
|
After Width: | Height: | Size: 79 KiB |
BIN
_resources/33fe54064980572fe7f6d73007eb6f5c.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
_resources/3425d014a947b459d58a59d6f1a7b43b.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
_resources/346b020fe6804da78af6f91d63c6aa46.png
Normal file
|
After Width: | Height: | Size: 190 KiB |
BIN
_resources/346c1acd8bcb0fbd62651c952a020f92.png
Normal file
|
After Width: | Height: | Size: 403 KiB |
BIN
_resources/34a0e6c7e86293c28495ad00eae7d378.png
Normal file
|
After Width: | Height: | Size: 302 KiB |
BIN
_resources/36929d18ce3ae958f8e5ac9cc7567abe.png
Normal file
|
After Width: | Height: | Size: 257 KiB |
BIN
_resources/374c672b4e1fc41476cd288fb321fa6c.png
Normal file
|
After Width: | Height: | Size: 482 KiB |
BIN
_resources/3792049ef2150220b22a1bb3c6cfe692.png
Normal file
|
After Width: | Height: | Size: 203 KiB |
BIN
_resources/37fd67ae56fd0f4487e84586dc8630e2.png
Normal file
|
After Width: | Height: | Size: 425 KiB |
BIN
_resources/382d1d6bc0ba5ab89cdf451653cf7827.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
_resources/385bd48553ca306d39e01d1c8f1d065e.png
Normal file
|
After Width: | Height: | Size: 136 KiB |
BIN
_resources/3d430e984fae82dde78badf4b729f50b.png
Normal file
|
After Width: | Height: | Size: 978 KiB |
BIN
_resources/4217b4369deda2ec9741b04cb27b67b6.png
Normal file
|
After Width: | Height: | Size: 99 KiB |
BIN
_resources/4259a2dba0bfe5fc0527f1ac50bb13b1.png
Normal file
|
After Width: | Height: | Size: 198 KiB |
BIN
_resources/468df77b58e1a69da3c0115bee1c4307.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
_resources/49447b505b41eded9c94a9bff174947d.png
Normal file
|
After Width: | Height: | Size: 401 KiB |
BIN
_resources/4a446c943be0caed43737e8e4363ea50.png
Normal file
|
After Width: | Height: | Size: 395 KiB |
BIN
_resources/4a49dcf8534d1694db35fe11f77a674e.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
_resources/4ad5c9f3bf9e3e9f50697319ea33ec04.png
Normal file
|
After Width: | Height: | Size: 462 KiB |
BIN
_resources/4b21323fadde3da88a58fa1efe8b2074.png
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
_resources/4c9bf833fd2ee0a0a80cfe8cf084cfb5.png
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
_resources/4fa99c7ed58f4879895649bee949120d.png
Normal file
|
After Width: | Height: | Size: 324 KiB |
BIN
_resources/52f67f89112c7000e4a9101645d40bfb.png
Normal file
|
After Width: | Height: | Size: 9.1 KiB |
BIN
_resources/54b1faab769043a3441643b1c54bacad.png
Normal file
|
After Width: | Height: | Size: 699 KiB |
BIN
_resources/55cc4c996c37f051a4bd82217ef90c3a.png
Normal file
|
After Width: | Height: | Size: 82 KiB |
BIN
_resources/5719f80d5a9d122e8691c52648e90f60.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
_resources/58a4df88506057184ffb8054b4d63784.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
_resources/59186eb638f7630a7eb38bc5aa9a873a.png
Normal file
|
After Width: | Height: | Size: 370 KiB |
BIN
_resources/5b3017e7d43fc6649ba389975c552669.png
Normal file
|
After Width: | Height: | Size: 411 KiB |
BIN
_resources/5b63409ee09e83ddf25c12f9aa239c0c.png
Normal file
|
After Width: | Height: | Size: 241 KiB |
BIN
_resources/5cb5a2e8a625f063081e5bead03ef547.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
_resources/5ce456f2f04a3c7694fe75c00c935acb.png
Normal file
|
After Width: | Height: | Size: 86 KiB |
BIN
_resources/6050d32bbccd78e38d779e2488e259bd.png
Normal file
|
After Width: | Height: | Size: 505 KiB |
BIN
_resources/6556aecaa3e434aa5769bd62dcdcb74a.png
Normal file
|
After Width: | Height: | Size: 247 KiB |
BIN
_resources/66c83e11b1fecf325f260f1875260a54.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
_resources/679ae4ae6918fb696965d56e43213749.png
Normal file
|
After Width: | Height: | Size: 147 KiB |
BIN
_resources/6ab5db7b6fde89f907e0509a40c873d9.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
_resources/6b9dcf55ac44067f31e11d003989d1fe.png
Normal file
|
After Width: | Height: | Size: 172 KiB |
BIN
_resources/6d57ac6198a3e6ab73f0434570274c94.png
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
_resources/6ec7276be266fd10cc77057d9dfc76d1.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
_resources/6edb124a9296a65e58971e1de0077629.png
Normal file
|
After Width: | Height: | Size: 167 KiB |
BIN
_resources/6ff7a61bc8763760d8b228208bbfb07f.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
_resources/72f71c083a32dcfdf87ae3ba9ed6d614.png
Normal file
|
After Width: | Height: | Size: 206 KiB |
BIN
_resources/7342d910f2dc61fc0c63d87ed4936264.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
_resources/7616ab6198c376cc0e4a25b02405dd59.png
Normal file
|
After Width: | Height: | Size: 156 KiB |
BIN
_resources/764c7f377091033262190448212db4e5.png
Normal file
|
After Width: | Height: | Size: 126 KiB |
BIN
_resources/76e14ea51e7166b22c55f3cd00ee55c3.png
Normal file
|
After Width: | Height: | Size: 383 KiB |
BIN
_resources/7c2152bc0ec8f03902aded1280ca0afc.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
_resources/7f1412996428b19d696c5cf406d5a558.png
Normal file
|
After Width: | Height: | Size: 528 KiB |
BIN
_resources/806ab46a3d11ebdd3d3d54109f75f173.png
Normal file
|
After Width: | Height: | Size: 278 KiB |
BIN
_resources/80cbcf5c89cc7523d2eee35766997ee0.png
Normal file
|
After Width: | Height: | Size: 467 KiB |
BIN
_resources/81a0b2112819f198e44ccad519dd09b2.png
Normal file
|
After Width: | Height: | Size: 324 KiB |
BIN
_resources/8266c37711f9f3f78883deb3111d58fd.png
Normal file
|
After Width: | Height: | Size: 350 KiB |
BIN
_resources/839f43ee9063f6d8db32e3fbeeebe3e9.png
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
_resources/8422cbfcb1b4ed8277ec50120017726a.png
Normal file
|
After Width: | Height: | Size: 374 KiB |
BIN
_resources/88ca8820e6b0ebb8e7495d5ddd8f1cf7.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
_resources/8d6701c74b6fe0c0c8e567dba819b36c.png
Normal file
|
After Width: | Height: | Size: 811 KiB |
BIN
_resources/8e27f90cf1d8e785503f9f1b3b976308.png
Normal file
|
After Width: | Height: | Size: 194 KiB |
2231
_resources/90 Common HTTP Status Codes_ Full Reference _ Tria.html
Normal file
BIN
_resources/929b7cd5a0ec2b5a24e845e33d790b83.png
Normal file
|
After Width: | Height: | Size: 135 KiB |
BIN
_resources/9531fc7c54bfb4c303be49d30f3b7d29.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
_resources/95bfea8e37d940bf5923d25fe037d8c4.png
Normal file
|
After Width: | Height: | Size: 298 KiB |
BIN
_resources/9a6a085c63fcaeb121f425de0d03d4b0.png
Normal file
|
After Width: | Height: | Size: 142 KiB |
BIN
_resources/9af98ea32bb21f3afd1d6ca1f8ebdc46.png
Normal file
|
After Width: | Height: | Size: 312 KiB |
BIN
_resources/9c50df0b4457b020a2326c1d18c956bf.png
Normal file
|
After Width: | Height: | Size: 100 KiB |
BIN
_resources/9eca3860ce3894c4dbf85b4e305bb2f1.png
Normal file
|
After Width: | Height: | Size: 434 KiB |
BIN
_resources/A File Icon.sublimepackage
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<!DOCTYPE html> <html lang=en><!--
|
||||
Page saved with SingleFile
|
||||
url: https://keepitfree.ai/it/announcements/a/i-chiude-restare-umani/
|
||||
saved date: Tue Sep 15 2026 12:00:45 GMT+0530 (India Standard Time)
|
||||
--><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><title>A/I Closes Stay Human · Keep the Internet free</title><style>:root{color-scheme:light;--fg:#1a1a1a;--bg:#ffffff;--muted:#6b6b6b;--accent:#cc0000}*{box-sizing:border-box}body{margin:0;font:16px/1.6 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;color:var(--fg);background:var(--bg);display:flex;flex-direction:column;min-height:100vh}header,main,footer{width:100%;max-width:58rem;margin-left:auto;margin-right:auto;padding:1.5rem}main{flex:1 0 auto}header{display:flex;justify-content:space-between;align-items:flex-start;flex-wrap:wrap;gap:0.5rem 1rem}.site-id{max-width:100%}.site-title{font-weight:700;text-decoration:none;color:var(--accent)}.site-subtitle{margin:0.2rem 0 0;color:var(--muted);font-size:0.95rem}nav a{margin-left:1rem;color:var(--accent);text-decoration:none}nav a:first-child{margin-left:0}.lang-switch{flex-basis:100%;font-size:0.85rem;margin-bottom:-0.75rem}.lang-switch a,.lang-switch .lang-current{margin-left:1rem}.lang-switch a:first-child{margin-left:0}.lang-switch .lang-current{color:var(--muted);font-weight:700}a{color:var(--accent)}h1{line-height:1.25}article{max-width:42rem}article time{display:block;margin:0.25rem 0 1.5rem;color:var(--muted);font-size:0.9rem}footer{flex-shrink:0;margin-top:2rem;color:var(--muted);font-size:0.8rem}footer .kaos{font-family:Helvetica,"Helvetica Neue",Arial,sans-serif;font-weight:900;color:var(--fg);letter-spacing:-0.01em;-webkit-text-stroke:0.4px var(--fg)}footer .rss-badge{background:red;color:#fff;padding:0.05rem 0.35rem;border-radius:2px;text-decoration:none;font-weight:700}</style><meta name=referrer content=no-referrer><link rel=canonical href=https://keepitfree.ai/it/announcements/a/i-chiude-restare-umani/><meta http-equiv=content-security-policy content="default-src 'none'; font-src 'self' data:; img-src 'self' data:; style-src 'unsafe-inline'; media-src 'self' data:; script-src 'unsafe-inline' data:; object-src 'self' data:; frame-src 'self' data:;"><body><header><div class=site-id><a class=site-title href=https://keepitfree.ai/it/>Keep the Internet free</a><p class=site-subtitle>We are not terrorists. Autistici.org is an infrastructure of dissent</p></div><nav><a href=https://keepitfree.ai/it/announcements>Press Releases</a>
|
||||
<a href=https://keepitfree.ai/it/technical-updates>Technical updates</a>
|
||||
<a href=https://keepitfree.ai/it/press-coverage>Press review</a>
|
||||
<a href=https://keepitfree.ai/it/solidarity>Solidarity</a>
|
||||
<a href=https://keepitfree.ai/it/events>Events</a></nav><nav class=lang-switch><a href=https://keepitfree.ai/announcements/a/i-shuts-down-stay-human/>English</a>
|
||||
<span class=lang-current>Italian</span></nav></header><main><article><h1>A/I closes - Stay Human</h1><time datetime=2026-09-06>Sep 6, 2026</time><p>As soon as we found out that we had ended up on the list of global terrorist organizations, we wrote, declared and promised that we would try to resist until it was possible, that we would not give up until we saw legal possibilities. We have proudly maintained and defended a free, reserved, autonomous and above all partisan infrastructure.<p>For us <strong>to remain human</strong> is not a simple slogan. <p>It means that, first of all, it is the users, the people who build the human networks to which we rely and the communities that have flooded us with messages and love and solidarity, which must be protected. <p>We cannot accept a clash or lend ourselves to instrumentalizations that endanger their lives, the lives of their loved ones, leaving them at the mercy of autocrats, fascists and agencies acting by extra-legal means. The concrete possibility of being able to be the cause of criminal or financial consequences for someone close to us, or who even interacts with us does not allow us other choices. <p><strong>A/I closes. The Autistic/Invented collective closes and will suspend all short-term services.</strong> <p><strong>There is no easy way to say it or explain it.</strong> <p>Every day we stayed online starting August 26 was a win, but we have to stop today.<p>None of us have sympathy for heroic gestures and least of all for the martyrs, so we will not do it and we will not ask for it. In this climate, continuing to offer our services is only one more danger to our users, and to all the people who are part of our communities. In a world of accusations unrelated to the facts we can only expect further disproportionate repression. This puts us in front of the impossibility of maintaining our original project: offering safe and uncommodified tools.<p><strong>It's been 25 years. It was a “good story.”</strong> <p><strong>Now drop the PC, go out, fight, hug and don't lose your smile. Because we stop. But resistance and ideas don't. We remain human.</strong><p>We will soon explain how to save the content of blogs, emails, sites and other technical suggestions. Keep in mind, however, that, as the autistici.org domain has been closed without any warning, in the meantime there may be other such problems that we are not able to predict. <p><strong>Autistic/Invented Collective</strong></p></article></main><footer><span class=kaos>+KAOS</span> — Collective Autistici/Invented <a href=https://inventati.org/>https://inventati.org</a> — <a href=mailto:ai-press@squat.net>ai-press@squat.net</a> — <a class=rss-badge href=https://keepitfree.ai/it/index.xml>RSS</a></footer>
|
||||
BIN
_resources/Autoruns.zip
Normal file
BIN
_resources/Babel.sublimepackage
Normal file
BIN
_resources/Box - Pronto User Documentation.pdf
Normal file
BIN
_resources/Cordova_Website_To_App_Conversion_new.pdf
Normal file
1470
_resources/DistroWatch.com_ Put the fun back into computing. .html
Normal file
BIN
_resources/Emmet.sublimepackage
Normal file
BIN
_resources/FileIcons.sublimepackage
Normal file
BIN
_resources/Go by Example_ Regular Expressions.pdf
Normal file
BIN
_resources/IMG_20230905_144031.jpg
Normal file
|
After Width: | Height: | Size: 110 KiB |
1280
_resources/Instances · TeamPiped_Piped Wiki · GitHub (11_10_2.html
Normal file
BIN
_resources/Material Theme.sublimepackage
Normal file
BIN
_resources/NB0_Tools_FIH_Mobile_v3.4.zip
Normal file
BIN
_resources/Oceanic Next Color Scheme.sublimepackage
Normal file
BIN
_resources/RainbowBrackets.sublimepackage
Normal file
|
After Width: | Height: | Size: 557 KiB |
BIN
_resources/SideBarEnhancements.sublimepackage
Normal file
BIN
_resources/SingleFile.crx
Normal file
BIN
_resources/SingleFile.zip
Normal file
17
_resources/Spreadsheet (16_10_2026 9:09:24 pm).html
Normal file
BIN
_resources/TelegramFUSE-main.zip
Normal file
BIN
_resources/Theme - Midnight.sublimepackage
Normal file
BIN
_resources/Untitled 1-1.png
Normal file
|
After Width: | Height: | Size: 564 KiB |
BIN
_resources/Untitled 1-2.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
_resources/Untitled 1-3.png
Normal file
|
After Width: | Height: | Size: 259 KiB |
BIN
_resources/Untitled 1-4.png
Normal file
|
After Width: | Height: | Size: 152 KiB |
BIN
_resources/Untitled 1-5.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
_resources/Untitled 1.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
_resources/Untitled 2-1.png
Normal file
|
After Width: | Height: | Size: 765 KiB |
BIN
_resources/Untitled 2-2.png
Normal file
|
After Width: | Height: | Size: 369 KiB |
BIN
_resources/Untitled 2-3.png
Normal file
|
After Width: | Height: | Size: 230 KiB |
BIN
_resources/Untitled 2-4.png
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
BIN
_resources/Untitled 2.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
_resources/Untitled 3-1.png
Normal file
|
After Width: | Height: | Size: 126 KiB |
BIN
_resources/Untitled 3.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
_resources/Untitled 4-1.png
Normal file
|
After Width: | Height: | Size: 137 KiB |
BIN
_resources/Untitled 4.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
_resources/Untitled 5.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
_resources/Untitled 6.png
Normal file
|
After Width: | Height: | Size: 2.6 MiB |
BIN
_resources/Untitled 7.png
Normal file
|
After Width: | Height: | Size: 2.7 MiB |
BIN
_resources/Untitled 8.png
Normal file
|
After Width: | Height: | Size: 3.1 MiB |
BIN
_resources/Untitled 9.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
_resources/Untitled-1.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
_resources/Untitled-2.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
_resources/Untitled-3.png
Normal file
|
After Width: | Height: | Size: 123 KiB |
BIN
_resources/Untitled-4.png
Normal file
|
After Width: | Height: | Size: 519 KiB |
BIN
_resources/Untitled-5.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
_resources/Untitled-6.png
Normal file
|
After Width: | Height: | Size: 122 KiB |
BIN
_resources/Untitled-7.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
_resources/Untitled-8.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
_resources/Untitled.png
Normal file
|
After Width: | Height: | Size: 519 KiB |
BIN
_resources/Using Postgres - Synapse.pdf
Normal file
45
_resources/Web Hosting (10_26_2023 7_15_20 PM).html
Normal file
BIN
_resources/WinRAR_crack.rar
Normal file
BIN
_resources/Windows10Debloater-master.zip
Executable file
BIN
_resources/a1e2e4ee308188a160d944eae7fb07b7.png
Normal file
|
After Width: | Height: | Size: 136 KiB |
BIN
_resources/a357f658bd6b32ebe4584769b0f29942.png
Normal file
|
After Width: | Height: | Size: 244 KiB |
BIN
_resources/a40ea2a8fa99b25b1fd49c2b3e6bdf90.png
Normal file
|
After Width: | Height: | Size: 128 KiB |
BIN
_resources/a549446a92e0e2344cd39f2649febbe3.png
Normal file
|
After Width: | Height: | Size: 363 KiB |
BIN
_resources/a5f845ee2814638022142ba0d085e9f2.png
Normal file
|
After Width: | Height: | Size: 955 KiB |
BIN
_resources/a64b5334b1ff34339d59aadab1fba034.png
Normal file
|
After Width: | Height: | Size: 382 KiB |
BIN
_resources/a706b53e056d4983c9411a8a07830fb7.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
_resources/a7d0a4ecdd2ac1a4b1c7fedd140f2c08.png
Normal file
|
After Width: | Height: | Size: 359 KiB |
BIN
_resources/a869ee6a00e12d5a57003c1372679492.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
_resources/aaron-bond.better-comments-3.0.2.zip
Normal file
BIN
_resources/aaronpowell.vscode-profile-switcher-0.4.0.zip
Normal file
BIN
_resources/add_gpedit_msc_by_drudger_d3kh6vm.zip
Normal file
BIN
_resources/ae523bc3c363436bc9fc6fee1aaa7aaf.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
_resources/android java app.7z
Normal file
89
_resources/android-sdk-installation.md
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
Android emulator on linux
|
||||
|
||||
- https://repodev.com/blog/install-android-sdk-without-android-studio
|
||||
- https://stackoverflow.com/questions/70752639/i-need-to-install-android-api-30-but-i-cannot-see-that-api-in-the-sdk-platform
|
||||
https://dl.google.com/android/repository/sys-img/google_apis/x86-30_r09.zip : for downloadng system images
|
||||
https://androidsdkmanager.azurewebsites.net/SDKPlatform
|
||||
|
||||
|
||||
- Download commandlinetools and gradle
|
||||
https://www.mediafire.com/file/zjubjy2d2nmblwf/commandlinetools-linux-10406996_latest.zip/file
|
||||
https://www.mediafire.com/file/26sokfserayh28a/gradle-8.5-bin.zip/file
|
||||
|
||||
Or use official sites
|
||||
https://developer.android.com/studio/index.html#command-line-tools-only
|
||||
https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip : ddl link for cmdtools
|
||||
https://gradle.org/releases/ : for gradle
|
||||
|
||||
- Files hierarchy
|
||||
```
|
||||
/home/username/bin/android/sdk/cmdline-tools/latest/
|
||||
|_bin/
|
||||
|_lib/
|
||||
|_NOTICE.txt
|
||||
|_source.properties
|
||||
|
||||
/home/username/bin/android/gradle/gradle-x.x.x/
|
||||
|_bin/
|
||||
|_docs/
|
||||
|_init.d/
|
||||
|_lib/
|
||||
|_src/
|
||||
|_LICENSE
|
||||
|_NOTICE
|
||||
|_README
|
||||
```
|
||||
- Go to bin directory for cmdtools
|
||||
Then
|
||||
` ./sdkmanager "platforms;android-30" "system-images;android-30;google_apis;x86_64" "platform-tools"`
|
||||
`./sdkmanager --licenses`
|
||||
Also install these
|
||||
`sudo pacman -S libmtp android-tools android-udev`
|
||||
|
||||
- Add path in `.bashrc`
|
||||
```
|
||||
vi ~/.bashrc
|
||||
# Android SDK files
|
||||
export ANDROID_HOME="$HOME/bin/android/sdk"
|
||||
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools
|
||||
# Gradle
|
||||
export PATH=$PATH:$HOME/bin/android/gradle/gradle-x.x/bin
|
||||
```
|
||||
|
||||
- Running
|
||||
Create avd
|
||||
`avdmanager create avd -n image_v29 -k "system-images;android-29;google_apis;x86_64"`
|
||||
` avdmanager list avd`
|
||||
|
||||
Start it by going to emulator directory then
|
||||
`./emulator -avd image_v29`
|
||||
|
||||
|
||||
- Android versions
|
||||
[android versions](:/8553c6956ef14eea9b578e3ba1ce5ad7)
|
||||
or
|
||||
https://developer.android.com/tools/releases/platforms
|
||||
|
||||
Open SDK Manager: First, locate and open the SDK Manager. You can find it in the tools directory of your Android SDK installation.
|
||||
|
||||
Launch SDK Manager: Run the sdkmanager command in your terminal or command prompt. Navigate to the tools/bin directory within your Android SDK installation and use the following command:
|
||||
|
||||
`sdkmanager --list`
|
||||
|
||||
This command will list all available packages and their versions.
|
||||
|
||||
Select and Install Previous Android Versions: Once you see the list of available packages, you can find the specific version you want to install. For instance, to install Android 9.0 (API level 28):
|
||||
|
||||
`sdkmanager "platforms;android-28"`
|
||||
|
||||
Replace "platforms;android-28" with the appropriate package name of the desired Android version. This command will download and install Android 9.0 (API level 28).
|
||||
|
||||
|
||||
Additional Components: If you need additional components such as system images or tools for a specific version, you can install them using similar commands:
|
||||
|
||||
|
||||
`sdkmanager "system-images;android-28;google_apis;x86_64"`
|
||||
|
||||
Again, adjust the package name to match the specific version and components you require.
|
||||
|
||||
|
||||
BIN
_resources/arch vm_outhostnamectl.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
_resources/arch_ueqfi_encryption_part_scheme.png
Normal file
|
After Width: | Height: | Size: 138 KiB |
BIN
_resources/autohotkey_wine_error.jpeg
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
_resources/awesome-api-clients-main.zip
Normal file
BIN
_resources/awesome-file-hosts-main.zip
Normal file
BIN
_resources/b07a3a4bd2f760bdf4870539fe58333f.png
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
_resources/b07c69aa4466bb2fc84630297b41983a.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
_resources/b0b2e7e0b4a84a18e328a6a58da63379.png
Normal file
|
After Width: | Height: | Size: 287 KiB |
BIN
_resources/b0d567574f579ff84e5a86a749c942b7.png
Normal file
|
After Width: | Height: | Size: 337 KiB |
BIN
_resources/b98495d939e02a55712241a4ee1d9c3c.png
Normal file
|
After Width: | Height: | Size: 263 KiB |
BIN
_resources/bbf332f396859a0251fcc20afe72173f.png
Normal file
|
After Width: | Height: | Size: 312 KiB |
BIN
_resources/bleachbit-4.4.2-4-any.pkg.tar.zst
Normal file
BIN
_resources/bleachbit-4.4.2-4-any.pkg.tar.zst.sig
Normal file
BIN
_resources/bleachbit_4.4.2-1_all.deb
Normal file
BIN
_resources/blesh bakup.7z
Normal file
BIN
_resources/boris io commands.png
Normal file
|
After Width: | Height: | Size: 54 KiB |
BIN
_resources/brave-browser-1.59.120-1-x86_64.pkg.tar.zst.sig
Normal file
BIN
_resources/bruno-main.zip
Normal file
BIN
_resources/bundles-master.zip
Normal file
BIN
_resources/c20044d8618a08d431037780900cc4ff.png
Normal file
|
After Width: | Height: | Size: 463 KiB |
BIN
_resources/c6eb4fe9ce57ef13adb62a43fcad45ff.png
Normal file
|
After Width: | Height: | Size: 180 KiB |
BIN
_resources/c70dcf4ec71045e65fa6f50e924a5054.png
Normal file
|
After Width: | Height: | Size: 297 KiB |
BIN
_resources/c9b95e2e3444f374a4c902fdb7634433.png
Normal file
|
After Width: | Height: | Size: 328 KiB |
BIN
_resources/ca5a8587755fcbeff4e7c3be830fdc79.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
_resources/cab00f7ebd8c4f0d838263c5f21dd8c7.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
_resources/cc82dca645b175b114ebd8e370002060.png
Normal file
|
After Width: | Height: | Size: 105 KiB |
BIN
_resources/cf9afb1ce388cc53cb4d2a535032e07c.png
Normal file
|
After Width: | Height: | Size: 63 KiB |
BIN
_resources/cfeaae3664097859094bd46e16924d96.png
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
_resources/chakrounanas.turbo-console-log-2.5.6.zip
Normal file
BIN
_resources/cloudflare-cors-anywhere-master.zip
Normal file
77
_resources/conditional widgets.txt
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
|
||||
|
||||
Actually you can use if/else and switch and any other statement inline in dart / flutter.
|
||||
Use a builder
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
if (true) //
|
||||
return "tis true";
|
||||
|
||||
return "anything but true";
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
or an immediate anonymous function
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
return Container(child: () {
|
||||
if (value == 1) {
|
||||
return Text('tis true');
|
||||
}
|
||||
return Text('anything but true');
|
||||
}());
|
||||
}
|
||||
|
||||
I would heavily recommend against putting too much logic directly with your UI 'markup' but I found that type inference in Dart needs a little bit of work so it can be sometimes useful in scenarios like that.
|
||||
Use the ternary operator
|
||||
|
||||
condition ? Text("True") : null,
|
||||
|
||||
Use If or For statements or spread operators in collections
|
||||
|
||||
children: [
|
||||
...manyItems,
|
||||
oneItem,
|
||||
if(canIKickIt)
|
||||
...kickTheCan
|
||||
for (item in items)
|
||||
Text(item)
|
||||
|
||||
Use a method
|
||||
|
||||
child: getWidget()
|
||||
|
||||
Widget getWidget() {
|
||||
if (x > 5) ...
|
||||
//more logic here and return a Widget
|
||||
|
||||
EDIT - new with Dart 3.0
|
||||
|
||||
Dart 3.0 adds new functionality such as if-case & switch expressions in order to use pattern matching, destructuring, guard clauses.
|
||||
https://dart.dev/language/patterns
|
||||
Switch Expressions
|
||||
|
||||
We can now use switch as an expression. https://dart.dev/language/branches#switch-expressions
|
||||
|
||||
child: switch (task) {
|
||||
Task_completed(:date) => Text("completed on $date"),
|
||||
Task_overdue(:priority) => Text("$priority"),
|
||||
},
|
||||
|
||||
if-case (new to Dart 3.0)
|
||||
|
||||
Use if-case instead of switch when you have a single or small number of conditions to check. https://dart.dev/language/branches#if-case
|
||||
|
||||
return ListView(children: [
|
||||
Text('header'),
|
||||
if (pair case [int x, int y]) //
|
||||
Text('Coordinates: ($x, $y)') //
|
||||
else
|
||||
Text('No coordinates given'),
|
||||
]);
|
||||
|
||||
312
_resources/config.json
Normal file
|
|
@ -0,0 +1,312 @@
|
|||
{
|
||||
"admin": {
|
||||
"endpointPrivate": null,
|
||||
"endpointPublic": null
|
||||
},
|
||||
"gateway": {
|
||||
"endpointPrivate": null,
|
||||
"endpointPublic": "ws://localhost:3001"
|
||||
},
|
||||
"cdn": {
|
||||
"endpointPrivate": "http://localhost:3001",
|
||||
"endpointPublic": "http://localhost:3001",
|
||||
"resizeHeightMax": 1000,
|
||||
"resizeWidthMax": 1000,
|
||||
"imagorServerUrl": null,
|
||||
"proxyCacheHeaderSeconds": 86400,
|
||||
"maxAttachmentSize": 26214400
|
||||
},
|
||||
"api": {
|
||||
"endpointPrivate": null,
|
||||
"endpointPublic": "http://localhost:3001",
|
||||
"defaultVersion": "9",
|
||||
"activeVersions": [
|
||||
"6",
|
||||
"7",
|
||||
"8",
|
||||
"9"
|
||||
]
|
||||
},
|
||||
"general": {
|
||||
"instanceName": "Spacebar Instance",
|
||||
"serverName": "http://localhost:3001",
|
||||
"instanceDescription": "This is a Spacebar instance made in the pre-release days",
|
||||
"frontPage": null,
|
||||
"tosPage": null,
|
||||
"correspondenceEmail": null,
|
||||
"correspondenceUserID": null,
|
||||
"image": null,
|
||||
"instanceId": "1471156511622377508",
|
||||
"autoCreateBotUsers": false
|
||||
},
|
||||
"limits": {
|
||||
"user": {
|
||||
"maxGuilds": 1048576,
|
||||
"maxUsername": 32,
|
||||
"maxFriends": 5000,
|
||||
"maxBio": 190
|
||||
},
|
||||
"guild": {
|
||||
"maxRoles": 1000,
|
||||
"maxEmojis": 2000,
|
||||
"maxStickers": 500,
|
||||
"maxMembers": 25000000,
|
||||
"maxChannels": 65535,
|
||||
"maxBulkBanUsers": 200,
|
||||
"maxChannelsInCategory": 65535
|
||||
},
|
||||
"message": {
|
||||
"maxCharacters": 1048576,
|
||||
"maxTTSCharacters": 160,
|
||||
"maxReactions": 2048,
|
||||
"maxAttachmentSize": 1073741824,
|
||||
"maxBulkDelete": 1000,
|
||||
"maxEmbedDownloadSize": 5242880,
|
||||
"maxPreloadCount": 100
|
||||
},
|
||||
"channel": {
|
||||
"maxPins": 500,
|
||||
"maxTopic": 1024,
|
||||
"maxWebhooks": 100
|
||||
},
|
||||
"rate": {
|
||||
"enabled": false,
|
||||
"ip": {
|
||||
"count": 500,
|
||||
"window": 5
|
||||
},
|
||||
"global": {
|
||||
"count": 250,
|
||||
"window": 5
|
||||
},
|
||||
"error": {
|
||||
"count": 10,
|
||||
"window": 5
|
||||
},
|
||||
"routes": {
|
||||
"guild": {
|
||||
"count": 5,
|
||||
"window": 5
|
||||
},
|
||||
"webhook": {
|
||||
"count": 10,
|
||||
"window": 5
|
||||
},
|
||||
"channel": {
|
||||
"count": 10,
|
||||
"window": 5
|
||||
},
|
||||
"auth": {
|
||||
"login": {
|
||||
"count": 5,
|
||||
"window": 60
|
||||
},
|
||||
"register": {
|
||||
"count": 2,
|
||||
"window": 43200
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"absoluteRate": {
|
||||
"register": {
|
||||
"limit": 25,
|
||||
"window": 3600000,
|
||||
"enabled": true
|
||||
},
|
||||
"sendMessage": {
|
||||
"limit": 200,
|
||||
"window": 60000,
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"security": {
|
||||
"captcha": {
|
||||
"enabled": false,
|
||||
"service": null,
|
||||
"sitekey": null,
|
||||
"secret": null
|
||||
},
|
||||
"twoFactor": {
|
||||
"generateBackupCodes": true
|
||||
},
|
||||
"autoUpdate": true,
|
||||
"requestSignature": "XK7aqpAC/uQ0cSos7zcR9E0sChYGj3cu1Fu/F+E6Jzw=",
|
||||
"jwtSecret": null,
|
||||
"forwardedFor": null,
|
||||
"trustedProxies": null,
|
||||
"abuseIpDbApiKey": null,
|
||||
"abuseipdbBlacklistRatelimit": 5,
|
||||
"abuseipdbConfidenceScoreTreshold": 50,
|
||||
"ipdataApiKey": null,
|
||||
"mfaBackupCodeCount": 10,
|
||||
"statsWorldReadable": true,
|
||||
"defaultRegistrationTokenExpiration": 604800000,
|
||||
"cdnSignUrls": false,
|
||||
"cdnSignatureKey": "T7j5+yP8pRPTteIULqu2pgaXxo3iSzYTyhz4McAMOTA=",
|
||||
"cdnSignatureDuration": "24h",
|
||||
"cdnSignatureIncludeIp": true,
|
||||
"cdnSignatureIncludeUserAgent": true
|
||||
},
|
||||
"login": {
|
||||
"requireCaptcha": false,
|
||||
"requireVerification": false
|
||||
},
|
||||
"register": {
|
||||
"email": {
|
||||
"required": false,
|
||||
"allowlist": false,
|
||||
"blocklist": true,
|
||||
"domains": []
|
||||
},
|
||||
"dateOfBirth": {
|
||||
"required": true,
|
||||
"minimum": 13
|
||||
},
|
||||
"password": {
|
||||
"required": false,
|
||||
"minLength": 8,
|
||||
"minNumbers": 2,
|
||||
"minUpperCase": 2,
|
||||
"minSymbols": 0
|
||||
},
|
||||
"disabled": false,
|
||||
"requireCaptcha": true,
|
||||
"requireInvite": false,
|
||||
"guestsRequireInvite": true,
|
||||
"allowNewRegistration": true,
|
||||
"allowMultipleAccounts": true,
|
||||
"blockIpDataCoThreatTypes": [
|
||||
"tor",
|
||||
"icloud_relay",
|
||||
"proxy",
|
||||
"datacenter",
|
||||
"anonymous",
|
||||
"known_attacker",
|
||||
"known_abuser",
|
||||
"threat"
|
||||
],
|
||||
"blockAsnTypes": [
|
||||
""
|
||||
],
|
||||
"blockAsns": [
|
||||
""
|
||||
],
|
||||
"blockAbuseIpDbAboveScore": 75,
|
||||
"incrementingDiscriminators": false,
|
||||
"defaultRights": "875069521787904",
|
||||
"checkIp": true
|
||||
},
|
||||
"regions": {
|
||||
"default": "spacebar",
|
||||
"useDefaultAsOptimal": true,
|
||||
"available": [
|
||||
{
|
||||
"id": "spacebar",
|
||||
"name": "spacebar",
|
||||
"endpoint": "127.0.0.1:3004",
|
||||
"vip": false,
|
||||
"custom": false,
|
||||
"deprecated": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"guild": {
|
||||
"discovery": {
|
||||
"showAllGuilds": false,
|
||||
"useRecommendation": false,
|
||||
"offset": 0,
|
||||
"limit": 24,
|
||||
"hideJoinedGuilds": true
|
||||
},
|
||||
"autoJoin": {
|
||||
"enabled": true,
|
||||
"guilds": [],
|
||||
"canLeave": true,
|
||||
"bots": false
|
||||
},
|
||||
"defaultFeatures": [],
|
||||
"publicThreadsInvitable": false
|
||||
},
|
||||
"gif": {
|
||||
"enabled": true,
|
||||
"provider": "tenor",
|
||||
"apiKey": "LIVDSRZULELA"
|
||||
},
|
||||
"rabbitmq": {
|
||||
"host": null
|
||||
},
|
||||
"templates": {
|
||||
"enabled": true,
|
||||
"allowTemplateCreation": true,
|
||||
"allowDiscordTemplates": true,
|
||||
"allowRaws": true
|
||||
},
|
||||
"defaults": {
|
||||
"guild": {
|
||||
"maxPresences": 250000,
|
||||
"maxVideoChannelUsers": 200,
|
||||
"afkTimeout": 300,
|
||||
"defaultMessageNotifications": 1,
|
||||
"explicitContentFilter": 0
|
||||
},
|
||||
"user": {
|
||||
"premium": true,
|
||||
"premiumType": 2,
|
||||
"verified": true
|
||||
}
|
||||
},
|
||||
"external": {
|
||||
"twitter": null
|
||||
},
|
||||
"email": {
|
||||
"provider": null,
|
||||
"senderAddress": null,
|
||||
"smtp": {
|
||||
"host": null,
|
||||
"port": null,
|
||||
"secure": null,
|
||||
"username": null,
|
||||
"password": null
|
||||
},
|
||||
"mailgun": {
|
||||
"username": null,
|
||||
"apiKey": null,
|
||||
"domain": null,
|
||||
"isEuropean": true
|
||||
},
|
||||
"mailjet": {
|
||||
"apiKey": null,
|
||||
"apiSecret": null
|
||||
},
|
||||
"sendgrid": {
|
||||
"apiKey": null
|
||||
}
|
||||
},
|
||||
"passwordReset": {
|
||||
"requireCaptcha": false
|
||||
},
|
||||
"user": {
|
||||
"blockedContains": [
|
||||
"discord",
|
||||
"clyde",
|
||||
"spacebar",
|
||||
"steam",
|
||||
"community",
|
||||
"support",
|
||||
"ticket"
|
||||
],
|
||||
"blockedEquals": [
|
||||
"everyone",
|
||||
"here"
|
||||
],
|
||||
"botsCanUseInvites": false
|
||||
},
|
||||
"offload": {
|
||||
"gateway": {
|
||||
"op12BaseUrl": null,
|
||||
"op14BaseUrl": null
|
||||
}
|
||||
}
|
||||
}
|
||||
2533
_resources/config.toml
Normal file
BIN
_resources/cpp imgui.7z
Normal file
BIN
_resources/css.pdf
Normal file
BIN
_resources/d2bc6210f22ed3406dc38acd75e05d66.png
Normal file
|
After Width: | Height: | Size: 113 KiB |
BIN
_resources/d6892ccd688cc45a47ac6e757cc3e1b7.png
Normal file
|
After Width: | Height: | Size: 524 KiB |
BIN
_resources/d725d061711e3414355818e78bbb8b5b.png
Normal file
|
After Width: | Height: | Size: 764 KiB |
BIN
_resources/d73d24177e74fae1908b9a43db77a0ed.png
Normal file
|
After Width: | Height: | Size: 58 KiB |
BIN
_resources/d8041f9ddaf662c8a6dda065e2b7e6ff.png
Normal file
|
After Width: | Height: | Size: 138 KiB |
73
_resources/dark theme i3.md
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
To set a global dark theme preference that modern Linux applications (GTK, Qt, Flatpaks, and Electron apps) automatically detect, you need to configure a few specific system flags. [1]
|
||||
Since you are running Cinnamon's underlying services alongside i3, applications look for XDG Desktop Portals, gsettings, and GTK/Qt system overrides to determine if the system is in dark mode.
|
||||
Here is how to set the global dark theme flags so your apps automatically adjust:
|
||||
## 1. Set the Global XDG Desktop Portal Flag (Most Important)
|
||||
Modern apps (including Flatpaks, Snap packages, Firefox, Chrome, and Electron apps) check the XDG Desktop Portal to see if the system prefers a dark layout. [2]
|
||||
Create or edit your local configuration file:
|
||||
|
||||
nano ~/.config/xdg-desktop-portal/settings.ini
|
||||
|
||||
Add the following lines to globally request dark appearance:
|
||||
|
||||
[org.freedesktop.appearance]
|
||||
color-scheme=1
|
||||
|
||||
(Note: 0 means default/no preference, 1 means prefer dark, and 2 means prefer light). [3, 4]
|
||||
## 2. Update the GSettings Framework
|
||||
Cinnamon and GNOME applications rely heavily on gsettings. Run these commands in your terminal to tell the system you prefer a dark color scheme and a dark GTK theme: [5, 6, 7]
|
||||
|
||||
# Tells modern apps to prefer dark layouts
|
||||
gsettings set org.gnome.desktop.interface color-scheme 'prefer-dark'
|
||||
# Sets the standard theme variant to dark
|
||||
gsettings set org.gnome.desktop.interface gtk-theme 'Adwaita-dark'
|
||||
|
||||
## 3. Configure the GTK 3 & 4 Config Files
|
||||
Some standalone applications bypass GSettings and check configuration files directly. Ensure your GTK files explicitly mandate the dark variant. [8, 9]
|
||||
Open or create the GTK 3 configuration file:
|
||||
|
||||
nano ~/.config/gtk-3.0/settings.ini
|
||||
|
||||
Ensure it contains these exact lines:
|
||||
|
||||
[Settings]
|
||||
gtk-theme-name=Adwaita-dark
|
||||
gtk-application-prefer-dark-theme=1
|
||||
|
||||
Repeat this process for GTK 4 applications:
|
||||
|
||||
nano ~/.config/gtk-4.0/settings.ini
|
||||
|
||||
Ensure it contains:
|
||||
|
||||
[Settings]
|
||||
gtk-theme-name=Adwaita-dark
|
||||
gtk-application-prefer-dark-theme=1
|
||||
|
||||
## 4. Force Qt Apps to Mimic GTK
|
||||
Qt-based applications (like VLC, KeepassXC, or qBittorrent) ignore GTK configurations by default. To force them to use your global GTK theme settings, add environmental variables to your profile. [10]
|
||||
Open your environment configuration:
|
||||
|
||||
sudo nano /etc/environment
|
||||
|
||||
Add these lines at the bottom:
|
||||
|
||||
QT_QPA_PLATFORMTHEME=gtk2
|
||||
QT_STYLE_OVERRIDE=adwaita-dark
|
||||
|
||||
## 5. Apply the Changes
|
||||
For these global flags to take full effect across all running daemons, save your files and restart your i3 session (press Mod+Shift+R or log out and log back in). [11]
|
||||
Once you log back in, your apps will read the active global flags and auto-adjust to their dark variants.
|
||||
If any specific application still refuses to flip over, let me know the name of the app or if it is installed as a Flatpak/Snap, and I can give you the target command to fix it!
|
||||
|
||||
[1] [https://www.baeldung.com](https://www.baeldung.com/linux/gtk-applications-dark-theme)
|
||||
[2] [https://www.reddit.com](https://www.reddit.com/r/xfce/comments/11pjosp/how_to_make_xfcefirefox_announce_light_dark_mode/)
|
||||
[3] [https://discussion.fedoraproject.org](https://discussion.fedoraproject.org/t/gnome-some-applications-launched-as-root-do-not-follow-dark-theme/78329)
|
||||
[4] [https://github.com](https://github.com/flatpak/xdg-desktop-portal/issues/629)
|
||||
[5] [https://blog.elementary.io](https://blog.elementary.io/dark-style-progress/)
|
||||
[6] [https://www.reddit.com](https://www.reddit.com/r/linuxmasterrace/comments/yubcik/does_anyone_know_how_to_change_the_default/)
|
||||
[7] [https://github.com](https://github.com/hyprwm/Hyprland/discussions/5867)
|
||||
[8] [https://github.com](https://github.com/linuxmint/cinnamon/issues/12994)
|
||||
[9] [https://orioninsist.medium.com](https://orioninsist.medium.com/true-system-wide-dark-mode-on-sway-wayland-e88c5226a22d)
|
||||
[10] [https://www.reddit.com](https://www.reddit.com/r/Ubuntu/comments/qbam6e/why_isnt_dark_theme_working_on_all_application/)
|
||||
[11] [https://forum.manjaro.org](https://forum.manjaro.org/t/changing-theme-appending-colour-palettes-in-config/58845)
|
||||
|
||||
BIN
_resources/dc332a02b2357d6530410381b3056230.png
Normal file
|
After Width: | Height: | Size: 397 KiB |
BIN
_resources/dd37075b960f36e6595d582e9c0e6acb.png
Normal file
|
After Width: | Height: | Size: 149 KiB |
BIN
_resources/dda32c58411fd49ead491fe54ceaf0b5.png
Normal file
|
After Width: | Height: | Size: 348 KiB |
47
_resources/designs ui.txt
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
Yes, Material Design is a prominent design language developed by Google, primarily for Android, but also used on other platforms. There are other design systems and languages with similar goals of providing a consistent and user-friendly experience. Here are some notable examples:
|
||||
|
||||
1. Cupertino (iOS Human Interface Guidelines):
|
||||
|
||||
Developed by Apple for iOS, iPadOS, macOS, watchOS, and tvOS.
|
||||
Focuses on clarity, deference (letting content take center stage), and depth (using visual layers and motion to convey hierarchy).
|
||||
Emphasizes translucency, blurring, and realistic motion effects.
|
||||
2. Fluent Design System (Microsoft):
|
||||
|
||||
Developed by Microsoft for Windows 10 and later, as well as other Microsoft products and services.
|
||||
Emphasizes light, depth, motion, material, and scale to create a more engaging and intuitive user experience.
|
||||
Key aspects include acrylic material (translucent backgrounds), reveal highlight (subtle lighting effects), and connected animations.
|
||||
3. Samsung One UI:
|
||||
|
||||
Developed by Samsung for its Galaxy devices (smartphones, tablets, wearables).
|
||||
Built upon Android but with customizations and additions to create a distinct Samsung experience.
|
||||
Focuses on one-handed usability, clean aesthetics, and intuitive interactions.
|
||||
4. LG UX:
|
||||
|
||||
Developed by LG for its electronic devices.
|
||||
Aims for a simple, clean, and consistent user experience.
|
||||
Adapts to different screen sizes and device types.
|
||||
5. Huawei HarmonyOS Design:
|
||||
|
||||
Developed by Huawei for its HarmonyOS platform.
|
||||
Focuses on creating a seamless experience across different devices.
|
||||
Emphasizes distributed design principles.
|
||||
6. Ant Design:
|
||||
|
||||
A design system for enterprise-level products, primarily web-based.
|
||||
Developed by Ant Group (an affiliate of Alibaba).
|
||||
Offers a comprehensive set of UI components and design resources.
|
||||
7. IBM Carbon Design System:
|
||||
|
||||
Another enterprise-level design system used by IBM.
|
||||
Provides guidance and resources for creating consistent and accessible user interfaces.
|
||||
8. Photon Design System (GNOME):
|
||||
|
||||
Used in the GNOME desktop environment and applications.
|
||||
Focuses on simplicity, accessibility, and consistency.
|
||||
Key Differences and Considerations:
|
||||
|
||||
Platform Focus: While some design systems are cross-platform, many are specifically tailored to a particular operating system or ecosystem (e.g., Cupertino for iOS, Fluent Design for Windows).
|
||||
Design Principles: Each design system has its own set of core principles and philosophies that guide the creation of user interfaces.
|
||||
Visual Style: Design systems differ in their visual styles, use of typography, color palettes, and animation styles.
|
||||
Component Libraries: Many design systems offer UI component libraries or frameworks that make it easier to implement the design language in your applications.
|
||||
When choosing a design system, consider the target platform, the overall aesthetic you want to achieve, and the availability of resources and tools. Material Design, Cupertino, and Fluent Design are the most prominent and widely used design systems for mobile and desktop platforms. The others are often tied to specific manufacturers or ecosystems. Ant Design and IBM Carbon are popular choices in the enterprise software space.
|
||||
BIN
_resources/df489f8d73a0478a32d881d677a3d05f.png
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
_resources/discordgo-master.zip
Normal file
BIN
_resources/dpkg alias.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
_resources/dsznajder.es7-react-js-snippets-4.4.3.zip
Normal file
BIN
_resources/e39413e48b0043e492bc1dc3ee14600f.png
Normal file
|
After Width: | Height: | Size: 390 KiB |
BIN
_resources/e819a660ea443a29cd650b8072b17824.png
Normal file
|
After Width: | Height: | Size: 363 KiB |
194
_resources/editForm.html
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
<form class="px-4 md:px-8 max-w-3xl mx-auto py-12">
|
||||
<div class="space-y-12">
|
||||
<div class="border-b border-gray-900/10 pb-12">
|
||||
<h2 class="text-base font-semibold leading-7 text-gray-900">Profile</h2>
|
||||
<p class="mt-1 text-sm leading-6 text-gray-600">This information will be displayed publicly so be careful what you
|
||||
share.</p>
|
||||
|
||||
<div class="mt-10 grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
|
||||
<div class="sm:col-span-4">
|
||||
<label for="username" class="block text-sm font-medium leading-6 text-gray-900">Username</label>
|
||||
<div class="mt-2">
|
||||
<div
|
||||
class="flex rounded-md shadow-sm ring-1 ring-inset ring-gray-300 focus-within:ring-2 focus-within:ring-inset focus-within:ring-indigo-600 sm:max-w-md">
|
||||
<span class="flex select-none items-center pl-3 text-gray-500 sm:text-sm">workcation.com/</span>
|
||||
<input type="text" name="username" id="username" autocomplete="username" class="block flex-1 border-0 bg-transparent py-1.5 pl-1 text-gray-900 placeholder:text-gray-400 focus:ring-0 sm:text-sm sm:leading-6" placeholder="janesmith">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-full">
|
||||
<label for="about" class="block text-sm font-medium leading-6 text-gray-900">About</label>
|
||||
<div class="mt-2">
|
||||
<textarea id="about" name="about" rows="3" class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6"></textarea>
|
||||
</div>
|
||||
<p class="mt-3 text-sm leading-6 text-gray-600">Write a few sentences about yourself.</p>
|
||||
</div>
|
||||
|
||||
<div class="col-span-full">
|
||||
<label for="photo" class="block text-sm font-medium leading-6 text-gray-900">Photo</label>
|
||||
<div class="mt-2 flex items-center gap-x-3">
|
||||
<svg class="h-12 w-12 text-gray-300" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
||||
<path fill-rule="evenodd"
|
||||
d="M18.685 19.097A9.723 9.723 0 0021.75 12c0-5.385-4.365-9.75-9.75-9.75S2.25 6.615 2.25 12a9.723 9.723 0 003.065 7.097A9.716 9.716 0 0012 21.75a9.716 9.716 0 006.685-2.653zm-12.54-1.285A7.486 7.486 0 0112 15a7.486 7.486 0 015.855 2.812A8.224 8.224 0 0112 20.25a8.224 8.224 0 01-5.855-2.438zM15.75 9a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0z"
|
||||
clip-rule="evenodd" />
|
||||
</svg>
|
||||
<button type="button" class="rounded-md bg-white px-2.5 py-1.5 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50">Change</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-full">
|
||||
<label for="cover-photo" class="block text-sm font-medium leading-6 text-gray-900">Cover photo</label>
|
||||
<div class="mt-2 flex justify-center rounded-lg border border-dashed border-gray-900/25 px-6 py-10">
|
||||
<div class="text-center">
|
||||
<svg class="mx-auto h-12 w-12 text-gray-300" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
||||
<path fill-rule="evenodd"
|
||||
d="M1.5 6a2.25 2.25 0 012.25-2.25h16.5A2.25 2.25 0 0122.5 6v12a2.25 2.25 0 01-2.25 2.25H3.75A2.25 2.25 0 011.5 18V6zM3 16.06V18c0 .414.336.75.75.75h16.5A.75.75 0 0021 18v-1.94l-2.69-2.689a1.5 1.5 0 00-2.12 0l-.88.879.97.97a.75.75 0 11-1.06 1.06l-5.16-5.159a1.5 1.5 0 00-2.12 0L3 16.061zm10.125-7.81a1.125 1.125 0 112.25 0 1.125 1.125 0 01-2.25 0z"
|
||||
clip-rule="evenodd" />
|
||||
</svg>
|
||||
<div class="mt-4 flex text-sm leading-6 text-gray-600">
|
||||
<label for="file-upload" class="relative cursor-pointer rounded-md bg-white font-semibold text-indigo-600 focus-within:outline-none focus-within:ring-2 focus-within:ring-indigo-600 focus-within:ring-offset-2 hover:text-indigo-500">
|
||||
<span>Upload a file</span>
|
||||
<input id="file-upload" name="file-upload" type="file" class="sr-only">
|
||||
</label>
|
||||
<p class="pl-1">or drag and drop</p>
|
||||
</div>
|
||||
<p class="text-xs leading-5 text-gray-600">PNG, JPG, GIF up to 10MB</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border-b border-gray-900/10 pb-12">
|
||||
<h2 class="text-base font-semibold leading-7 text-gray-900">Personal Information</h2>
|
||||
<p class="mt-1 text-sm leading-6 text-gray-600">Use a permanent address where you can receive mail.</p>
|
||||
|
||||
<div class="mt-10 grid grid-cols-1 gap-x-6 gap-y-8 sm:grid-cols-6">
|
||||
<div class="sm:col-span-3">
|
||||
<label for="first-name" class="block text-sm font-medium leading-6 text-gray-900">First name</label>
|
||||
<div class="mt-2">
|
||||
<input type="text" name="first-name" id="first-name" autocomplete="given-name" class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-3">
|
||||
<label for="last-name" class="block text-sm font-medium leading-6 text-gray-900">Last name</label>
|
||||
<div class="mt-2">
|
||||
<input type="text" name="last-name" id="last-name" autocomplete="family-name" class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-4">
|
||||
<label for="email" class="block text-sm font-medium leading-6 text-gray-900">Email address</label>
|
||||
<div class="mt-2">
|
||||
<input id="email" name="email" type="email" autocomplete="email" class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-3">
|
||||
<label for="country" class="block text-sm font-medium leading-6 text-gray-900">Country</label>
|
||||
<div class="mt-2">
|
||||
<select id="country" name="country" autocomplete="country-name" class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:max-w-xs sm:text-sm sm:leading-6">
|
||||
<option>United States</option>
|
||||
<option>Canada</option>
|
||||
<option>Mexico</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-full">
|
||||
<label for="street-address" class="block text-sm font-medium leading-6 text-gray-900">Street address</label>
|
||||
<div class="mt-2">
|
||||
<input type="text" name="street-address" id="street-address" autocomplete="street-address" class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-2 sm:col-start-1">
|
||||
<label for="city" class="block text-sm font-medium leading-6 text-gray-900">City</label>
|
||||
<div class="mt-2">
|
||||
<input type="text" name="city" id="city" autocomplete="address-level2" class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-2">
|
||||
<label for="region" class="block text-sm font-medium leading-6 text-gray-900">State / Province</label>
|
||||
<div class="mt-2">
|
||||
<input type="text" name="region" id="region" autocomplete="address-level1" class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-2">
|
||||
<label for="postal-code" class="block text-sm font-medium leading-6 text-gray-900">ZIP / Postal code</label>
|
||||
<div class="mt-2">
|
||||
<input type="text" name="postal-code" id="postal-code" autocomplete="postal-code" class="block w-full rounded-md border-0 py-1.5 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border-b border-gray-900/10 pb-12">
|
||||
<h2 class="text-base font-semibold leading-7 text-gray-900">Notifications</h2>
|
||||
<p class="mt-1 text-sm leading-6 text-gray-600">We'll always let you know about important changes, but you pick
|
||||
what else you want to hear about.</p>
|
||||
|
||||
<div class="mt-10 space-y-10">
|
||||
<fieldset>
|
||||
<legend class="text-sm font-semibold leading-6 text-gray-900">By Email</legend>
|
||||
<div class="mt-6 space-y-6">
|
||||
<div class="relative flex gap-x-3">
|
||||
<div class="flex h-6 items-center">
|
||||
<input id="comments" name="comments" type="checkbox" class="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-600">
|
||||
</div>
|
||||
<div class="text-sm leading-6">
|
||||
<label for="comments" class="font-medium text-gray-900">Comments</label>
|
||||
<p class="text-gray-500">Get notified when someones posts a comment on a posting.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative flex gap-x-3">
|
||||
<div class="flex h-6 items-center">
|
||||
<input id="candidates" name="candidates" type="checkbox" class="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-600">
|
||||
</div>
|
||||
<div class="text-sm leading-6">
|
||||
<label for="candidates" class="font-medium text-gray-900">Candidates</label>
|
||||
<p class="text-gray-500">Get notified when a candidate applies for a job.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative flex gap-x-3">
|
||||
<div class="flex h-6 items-center">
|
||||
<input id="offers" name="offers" type="checkbox" class="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-600">
|
||||
</div>
|
||||
<div class="text-sm leading-6">
|
||||
<label for="offers" class="font-medium text-gray-900">Offers</label>
|
||||
<p class="text-gray-500">Get notified when a candidate accepts or rejects an offer.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
<fieldset>
|
||||
<legend class="text-sm font-semibold leading-6 text-gray-900">Push Notifications</legend>
|
||||
<p class="mt-1 text-sm leading-6 text-gray-600">These are delivered via SMS to your mobile phone.</p>
|
||||
<div class="mt-6 space-y-6">
|
||||
<div class="flex items-center gap-x-3">
|
||||
<input id="push-everything" name="push-notifications" type="radio" class="h-4 w-4 border-gray-300 text-indigo-600 focus:ring-indigo-600">
|
||||
<label for="push-everything" class="block text-sm font-medium leading-6 text-gray-900">Everything</label>
|
||||
</div>
|
||||
<div class="flex items-center gap-x-3">
|
||||
<input id="push-email" name="push-notifications" type="radio" class="h-4 w-4 border-gray-300 text-indigo-600 focus:ring-indigo-600">
|
||||
<label for="push-email" class="block text-sm font-medium leading-6 text-gray-900">Same as email</label>
|
||||
</div>
|
||||
<div class="flex items-center gap-x-3">
|
||||
<input id="push-nothing" name="push-notifications" type="radio" class="h-4 w-4 border-gray-300 text-indigo-600 focus:ring-indigo-600">
|
||||
<label for="push-nothing" class="block text-sm font-medium leading-6 text-gray-900">No push notifications</label>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex items-center justify-end gap-x-6">
|
||||
<button type="button" class="text-sm font-semibold leading-6 text-gray-900">Cancel</button>
|
||||
<button type="submit" class="rounded-md bg-indigo-600 px-3 py-2 text-sm font-semibold text-white shadow-sm hover:bg-indigo-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-600">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
557
_resources/editForm2.html
Normal file
|
|
@ -0,0 +1,557 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Custom Audio Player with SVGs</title>
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"
|
||||
defer
|
||||
></script>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<style>
|
||||
.error-input {
|
||||
border-color: #ef4444 !important; /* Tailwind's red-500 */
|
||||
box-shadow: 0 0 0 1px #ef4444; /* optional subtle red glow */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-white dark:bg-gray-900 min-h-screen p-4">
|
||||
<section
|
||||
class="relative overflow-hidden min-h-screen bg-white dark:bg-gray-900 flex items-center justify-center py-12"
|
||||
>
|
||||
<!-- Background elements -->
|
||||
<div class="absolute inset-0 overflow-hidden">
|
||||
<div
|
||||
class="absolute -top-1/2 -right-1/2 bg-blue-400/20 dark:bg-blue-600/20 blur-3xl w-96 h-96 rounded-full"
|
||||
></div>
|
||||
<div
|
||||
class="absolute -bottom-1/2 -left-1/2 bg-purple-400/20 dark:bg-purple-600/20 blur-3xl w-96 h-96 rounded-full"
|
||||
></div>
|
||||
</div>
|
||||
|
||||
<div class="relative z-10 mx-auto px-4 w-full max-w-2xl">
|
||||
<!-- Header -->
|
||||
<div class="text-center mb-8">
|
||||
<h1
|
||||
class="text-3xl font-bold text-gray-900 leading-tight sm:text-4xl dark:text-white"
|
||||
>
|
||||
Complete Your Profile
|
||||
</h1>
|
||||
<p class="mt-2 text-gray-600 dark:text-gray-400">
|
||||
Tell us more about yourself to personalize your experience
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Profile Setup Form Container -->
|
||||
<div
|
||||
class="bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm rounded-2xl shadow-xl p-8 border border-gray-200/50 dark:border-gray-700/50"
|
||||
x-data="{
|
||||
submitting: false,
|
||||
showSuccess: false,
|
||||
formData: {
|
||||
avatar: '',
|
||||
firstName: '',
|
||||
lastName: '',
|
||||
bio: '',
|
||||
location: '',
|
||||
website: '',
|
||||
jobTitle: '',
|
||||
company: '',
|
||||
facebook: '',
|
||||
linkedin: ''
|
||||
},
|
||||
errors: {},
|
||||
|
||||
validateField(fieldName, value) {
|
||||
this.errors[fieldName] = '';
|
||||
|
||||
if (fieldName === 'firstName') {
|
||||
if (!value.trim()) return 'First name is required';
|
||||
}
|
||||
|
||||
if (fieldName === 'lastName') {
|
||||
if (!value.trim()) return 'Last name is required';
|
||||
}
|
||||
|
||||
if (fieldName === 'bio') {
|
||||
if (value.length > 200) return 'Bio must be less than 200 characters';
|
||||
}
|
||||
|
||||
if (fieldName === 'website') {
|
||||
if (value && !/^(https?:\/\/)?([\da-z.-]+)\.([a-z.]{2,6})([/\w .-]*)*\/?$/.test(value)) {
|
||||
return 'Please enter a valid website URL';
|
||||
}
|
||||
}
|
||||
|
||||
if (fieldName === 'facebook') {
|
||||
if (value && !/^(https?:\/\/)?(www\.)?facebook\.com\/[a-zA-Z0-9(\.\?)?]/.test(value)) {
|
||||
return 'Please enter a valid Facebook URL';
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
|
||||
validateForm() {
|
||||
this.errors = {};
|
||||
let isValid = true;
|
||||
|
||||
// Validate required fields
|
||||
Object.keys(this.formData).forEach(field => {
|
||||
if (field === 'firstName' || field === 'lastName') {
|
||||
const error = this.validateField(field, this.formData[field]);
|
||||
if (error) {
|
||||
this.errors[field] = error;
|
||||
isValid = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Validate optional fields if they have values
|
||||
['bio', 'website', 'facebook'].forEach(field => {
|
||||
if (this.formData[field]) {
|
||||
const error = this.validateField(field, this.formData[field]);
|
||||
if (error) {
|
||||
this.errors[field] = error;
|
||||
isValid = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return isValid;
|
||||
},
|
||||
|
||||
async submitForm() {
|
||||
if (!this.validateForm()) {
|
||||
// Scroll to first error
|
||||
const firstError = document.querySelector('.error-input');
|
||||
if (firstError) {
|
||||
firstError.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||
firstError.focus();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
this.submitting = true;
|
||||
|
||||
// Simulate API call
|
||||
await new Promise(resolve => setTimeout(resolve, 1500));
|
||||
|
||||
// Show success message
|
||||
this.showSuccess = true;
|
||||
this.submitting = false;
|
||||
},
|
||||
|
||||
handleAvatarUpload(event) {
|
||||
const file = event.target.files[0];
|
||||
if (file) {
|
||||
if (file.size > 2 * 1024 * 1024) { // 2MB limit
|
||||
alert('File size must be less than 2MB');
|
||||
return;
|
||||
}
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
this.formData.avatar = e.target.result;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
}
|
||||
}"
|
||||
>
|
||||
<!-- Profile Setup Form -->
|
||||
<form @submit.prevent="submitForm" x-show="!showSuccess" x-transition>
|
||||
<div class="space-y-8">
|
||||
<!-- Avatar Section -->
|
||||
<div class="text-center">
|
||||
<div class="avatar-upload inline-block mb-4 relative">
|
||||
<div
|
||||
class="relative w-32 h-32 mx-auto rounded-full border-2 border-dashed border-gray-300 dark:border-gray-600 flex items-center justify-center overflow-hidden"
|
||||
>
|
||||
<!-- Profile Image -->
|
||||
<template x-if="formData.avatar">
|
||||
<img
|
||||
:src="formData.avatar"
|
||||
alt="Profile preview"
|
||||
class="w-full h-full object-cover rounded-full"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<!-- Placeholder Icon -->
|
||||
<template x-if="!formData.avatar">
|
||||
<div
|
||||
class="flex items-center justify-center w-full h-full text-gray-400"
|
||||
>
|
||||
<svg
|
||||
class="w-12 h-12"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Hover Overlay -->
|
||||
<div
|
||||
class="absolute inset-0 bg-black bg-opacity-30 rounded-full flex items-center justify-center opacity-0 hover:opacity-100 transition-opacity duration-200 cursor-pointer"
|
||||
>
|
||||
<svg
|
||||
class="w-8 h-8 text-white"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z"
|
||||
></path>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M15 13a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<!-- Hidden File Input -->
|
||||
<input
|
||||
type="file"
|
||||
accept="image/*"
|
||||
@change="handleAvatarUpload"
|
||||
class="absolute inset-0 w-full h-full opacity-0 cursor-pointer rounded-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-sm text-gray-600 dark:text-gray-400">
|
||||
Click on the avatar to upload a profile picture
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Personal Information -->
|
||||
<div>
|
||||
<h3
|
||||
class="text-lg font-semibold text-gray-900 dark:text-white mb-4"
|
||||
>
|
||||
Personal Information
|
||||
</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label
|
||||
for="firstName"
|
||||
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
|
||||
>First Name</label
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
id="firstName"
|
||||
x-model="formData.firstName"
|
||||
@blur="errors.firstName = validateField('firstName', formData.firstName)"
|
||||
:class="errors.firstName ? 'error-input' : ''"
|
||||
class="w-full px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none transition-all duration-200"
|
||||
placeholder="John"
|
||||
/>
|
||||
<div
|
||||
x-show="errors.firstName"
|
||||
x-text="errors.firstName"
|
||||
class="mt-1 text-sm text-red-600 dark:text-red-400"
|
||||
></div>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
for="lastName"
|
||||
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
|
||||
>Last Name</label
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
id="lastName"
|
||||
x-model="formData.lastName"
|
||||
@blur="errors.lastName = validateField('lastName', formData.lastName)"
|
||||
:class="errors.lastName ? 'error-input' : ''"
|
||||
class="w-full px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none transition-all duration-200"
|
||||
placeholder="Doe"
|
||||
/>
|
||||
<div
|
||||
x-show="errors.lastName"
|
||||
x-text="errors.lastName"
|
||||
class="mt-1 text-sm text-red-600 dark:text-red-400"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bio -->
|
||||
<div>
|
||||
<label
|
||||
for="bio"
|
||||
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
|
||||
>Bio</label
|
||||
>
|
||||
<textarea
|
||||
id="bio"
|
||||
x-model="formData.bio"
|
||||
rows="3"
|
||||
@blur="errors.bio = validateField('bio', formData.bio)"
|
||||
:class="errors.bio ? 'error-input' : ''"
|
||||
class="w-full px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none transition-all duration-200"
|
||||
placeholder="Tell us a bit about yourself..."
|
||||
></textarea>
|
||||
<div class="flex justify-between mt-1">
|
||||
<div
|
||||
x-show="errors.bio"
|
||||
x-text="errors.bio"
|
||||
class="text-sm text-red-600 dark:text-red-400"
|
||||
></div>
|
||||
<div
|
||||
class="text-sm text-gray-500 dark:text-gray-400"
|
||||
x-text="`${200 - formData.bio.length} characters remaining`"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Professional Information -->
|
||||
<div>
|
||||
<h3
|
||||
class="text-lg font-semibold text-gray-900 dark:text-white mb-4"
|
||||
>
|
||||
Professional Information
|
||||
</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label
|
||||
for="jobTitle"
|
||||
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
|
||||
>Job Title</label
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
id="jobTitle"
|
||||
x-model="formData.jobTitle"
|
||||
class="w-full px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none transition-all duration-200"
|
||||
placeholder="Software Engineer"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
for="company"
|
||||
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
|
||||
>Company</label
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
id="company"
|
||||
x-model="formData.company"
|
||||
class="w-full px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none transition-all duration-200"
|
||||
placeholder="Acme Inc."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Location & Website -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label
|
||||
for="location"
|
||||
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
|
||||
>Location</label
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
id="location"
|
||||
x-model="formData.location"
|
||||
class="w-full px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none transition-all duration-200"
|
||||
placeholder="New York, NY"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
for="website"
|
||||
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
|
||||
>Website</label
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
id="website"
|
||||
x-model="formData.website"
|
||||
@blur="errors.website = validateField('website', formData.website)"
|
||||
:class="errors.website ? 'error-input' : ''"
|
||||
class="w-full px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none transition-all duration-200"
|
||||
placeholder="https://example.com"
|
||||
/>
|
||||
<div
|
||||
x-show="errors.website"
|
||||
x-text="errors.website"
|
||||
class="mt-1 text-sm text-red-600 dark:text-red-400"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Social Links -->
|
||||
<div>
|
||||
<h3
|
||||
class="text-lg font-semibold text-gray-900 dark:text-white mb-4"
|
||||
>
|
||||
Social Links
|
||||
</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label
|
||||
for="facebook"
|
||||
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1 flex items-center"
|
||||
>
|
||||
<svg
|
||||
class="w-4 h-4 mr-2 text-blue-600"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"
|
||||
/>
|
||||
</svg>
|
||||
Facebook
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="facebook"
|
||||
x-model="formData.facebook"
|
||||
@blur="errors.facebook = validateField('facebook', formData.facebook)"
|
||||
:class="errors.facebook ? 'error-input' : ''"
|
||||
class="w-full px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none transition-all duration-200"
|
||||
placeholder="https://facebook.com/username"
|
||||
/>
|
||||
<div
|
||||
x-show="errors.facebook"
|
||||
x-text="errors.facebook"
|
||||
class="mt-1 text-sm text-red-600 dark:text-red-400"
|
||||
></div>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
for="linkedin"
|
||||
class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1 flex items-center"
|
||||
>
|
||||
<svg
|
||||
class="w-4 h-4 mr-2 text-blue-600"
|
||||
fill="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M19 0h-14c-2.761 0-5 2.239-5 5v14c0 2.761 2.239 5 5 5h14c2.762 0 5-2.239 5-5v-14c0-2.761-2.238-5-5-5zm-11 19h-3v-11h3v11zm-1.5-12.268c-.966 0-1.75-.79-1.75-1.764s.784-1.764 1.75-1.764 1.75.79 1.75 1.764-.783 1.764-1.75 1.764zm13.5 12.268h-3v-5.604c0-3.368-4-3.113-4 0v5.604h-3v-11h3v1.765c1.396-2.586 7-2.777 7 2.476v6.759z"
|
||||
/>
|
||||
</svg>
|
||||
LinkedIn
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="linkedin"
|
||||
x-model="formData.linkedin"
|
||||
class="w-full px-4 py-3 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-white focus:outline-none transition-all duration-200"
|
||||
placeholder="linkedin.com/in/username"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="pt-4">
|
||||
<button
|
||||
type="submit"
|
||||
:disabled="submitting"
|
||||
class="w-full px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-70 disabled:cursor-not-allowed transition-colors duration-200 font-medium flex items-center justify-center"
|
||||
>
|
||||
<span x-show="!submitting">Complete Profile</span>
|
||||
<span x-show="submitting" class="flex items-center">
|
||||
<svg
|
||||
class="animate-spin -ml-1 mr-2 h-4 w-4 text-white"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<circle
|
||||
class="opacity-25"
|
||||
cx="12"
|
||||
cy="12"
|
||||
r="10"
|
||||
stroke="currentColor"
|
||||
stroke-width="4"
|
||||
></circle>
|
||||
<path
|
||||
class="opacity-75"
|
||||
fill="currentColor"
|
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||
></path>
|
||||
</svg>
|
||||
Saving Profile...
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Success Message -->
|
||||
<div
|
||||
x-show="showSuccess"
|
||||
x-transition:enter="transition ease-out duration-300"
|
||||
x-transition:enter-start="opacity-0 transform scale-95"
|
||||
x-transition:enter-end="opacity-100 transform scale-100"
|
||||
class="text-center py-8"
|
||||
>
|
||||
<div class="mb-4 flex justify-center">
|
||||
<div
|
||||
class="w-16 h-16 rounded-full bg-green-100 dark:bg-green-900 flex items-center justify-center success-checkmark"
|
||||
>
|
||||
<svg
|
||||
class="w-8 h-8 text-green-600 dark:text-green-400"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
stroke-width="2"
|
||||
d="M5 13l4 4L19 7"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<h3 class="text-2xl font-bold text-gray-900 dark:text-white mb-2">
|
||||
Profile Updated Successfully!
|
||||
</h3>
|
||||
<p class="text-gray-600 dark:text-gray-400 mb-6">
|
||||
Your profile has been updated with the new information.
|
||||
</p>
|
||||
<div class="flex space-x-4">
|
||||
<a
|
||||
href="#"
|
||||
class="flex-1 px-4 py-2 border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors duration-200 font-medium text-center"
|
||||
>
|
||||
View Profile
|
||||
</a>
|
||||
<a
|
||||
href="#"
|
||||
class="flex-1 px-4 py-2 bg-blue-600 text-white text-center rounded-lg hover:bg-blue-700 transition-colors duration-200 font-medium"
|
||||
>Go to Dashboard</a
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<p class="text-center">
|
||||
Get More Components | Templates in multiple Frameowkr by visiting
|
||||
<a href="https://wavykits.com" class="text-blue-600">wavykits.com</a>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
BIN
_resources/esbenp.prettier-vscode-9.9.0.7z
Normal file
BIN
_resources/express-template-main.zip
Normal file
BIN
_resources/f032aa6d3df03bc2c93731c03346a19e.png
Normal file
|
After Width: | Height: | Size: 116 KiB |
BIN
_resources/f0ee334262ce721ad99373bed5af9bcd.png
Normal file
|
After Width: | Height: | Size: 442 KiB |
BIN
_resources/f260be10c48c6fd437878a1074e7bb3a.png
Normal file
|
After Width: | Height: | Size: 866 KiB |
BIN
_resources/f2ea8455f4a7eb8c141ec7f64752c652.png
Normal file
|
After Width: | Height: | Size: 849 KiB |
BIN
_resources/f4b316229bc1b2a4386302713fffd1d1.png
Normal file
|
After Width: | Height: | Size: 470 KiB |
BIN
_resources/f5f4de7df0e5c0c10accfe9edc848e01.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
_resources/f83fc6b954ed77d200b5c0670d27ef10.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
_resources/fa1e7a12553815c724185b2d73fdd7f2.png
Normal file
|
After Width: | Height: | Size: 843 KiB |
BIN
_resources/fc066d5defa53327c9d453d63ebb0d78.png
Normal file
|
After Width: | Height: | Size: 535 KiB |
BIN
_resources/fccce4208ab8b92759d53376c89689f6.png
Normal file
|
After Width: | Height: | Size: 125 KiB |
BIN
_resources/firefox_extension_mess.png
Normal file
|
After Width: | Height: | Size: 161 KiB |
BIN
_resources/gdb-13.2-1-x86_64.pkg.tar.zst
Normal file
BIN
_resources/gdb-13.2-1-x86_64.pkg.tar.zst.sig
Normal file
BIN
_resources/gdb-common-13.2-1-x86_64.pkg.tar.zst
Normal file
BIN
_resources/gdb-common-13.2-1-x86_64.pkg.tar.zst.sig
Normal file
BIN
_resources/git-graph-1.31.0-beta.3.vsix
Normal file
BIN
_resources/go andlabs gui.7z
Normal file
BIN
_resources/go fyne gui.7z
Normal file
BIN
_resources/go wails gui.7z
Normal file
8
_resources/gpedit-enabler.bat
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
@echo off
|
||||
pushd "%~dp0"
|
||||
|
||||
dir /b %SystemRoot%\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientExtensions-Package~3*.mum >List.txt
|
||||
dir /b %SystemRoot%\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientTools-Package~3*.mum >>List.txt
|
||||
|
||||
for /f %%i in ('findstr /i . List.txt 2^>nul') do dism /online /norestart /add-package:"%SystemRoot%\servicing\Packages\%%i"
|
||||
pause
|
||||
BIN
_resources/grub_rescue_error.jpg
Normal file
|
After Width: | Height: | Size: 508 KiB |
BIN
_resources/heroku database_url.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
_resources/heroku env.png
Normal file
|
After Width: | Height: | Size: 226 KiB |
BIN
_resources/html.pdf
Normal file
BIN
_resources/java gui.7z
Normal file
17287
_resources/jornetlog.txt
Normal file
BIN
_resources/jprestidge.theme-material-theme-1.0.1.7z
Normal file
967
_resources/js-to-go.html
Normal file
|
|
@ -0,0 +1,967 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>JavaScript → Go — a phrasebook</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,300;12..96,400;12..96,500;12..96,700;12..96,800&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root{
|
||||
/* palette drawn from the two languages' own identities */
|
||||
--paper:#E7EDF1; /* cool godoc-ish paper */
|
||||
--card:#FFFFFF;
|
||||
--ink:#0B1215;
|
||||
--ink-soft:#5A6B76;
|
||||
--rule:#C9D5DD;
|
||||
--go:#00ADD8; /* gopher blue */
|
||||
--go-deep:#007D9C;
|
||||
--js:#F7DF1E; /* js yellow */
|
||||
--fuchsia:#CE3262; /* go brand fuchsia */
|
||||
--teal:#00776F; /* go brand aqua, darkened for contrast */
|
||||
|
||||
--mono:"JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,monospace;
|
||||
--sans:"Bricolage Grotesque","Helvetica Neue",Arial,sans-serif;
|
||||
}
|
||||
|
||||
*{box-sizing:border-box}
|
||||
html{scroll-behavior:smooth;scroll-padding-top:88px}
|
||||
body{
|
||||
margin:0;
|
||||
background:var(--paper);
|
||||
color:var(--ink);
|
||||
font-family:var(--sans);
|
||||
font-size:17px;
|
||||
line-height:1.5;
|
||||
-webkit-font-smoothing:antialiased;
|
||||
}
|
||||
a{color:var(--go-deep)}
|
||||
:focus-visible{outline:2.5px solid var(--fuchsia);outline-offset:3px;border-radius:2px}
|
||||
|
||||
.wrap{max-width:1180px;margin:0 auto;padding:0 24px}
|
||||
|
||||
/* ── sticky bar ─────────────────────────────── */
|
||||
.bar{
|
||||
position:sticky;top:0;z-index:50;
|
||||
background:rgba(231,237,241,.88);
|
||||
backdrop-filter:blur(10px);
|
||||
border-bottom:1px solid var(--rule);
|
||||
}
|
||||
.bar-in{display:flex;align-items:center;gap:20px;height:64px}
|
||||
.mark{
|
||||
font-family:var(--mono);font-size:13px;font-weight:700;
|
||||
letter-spacing:.08em;white-space:nowrap;text-decoration:none;color:var(--ink)
|
||||
}
|
||||
.mark em{font-style:normal;color:var(--fuchsia)}
|
||||
.mark b{font-weight:700;color:var(--go-deep)}
|
||||
.search{margin-left:auto;position:relative;display:flex;align-items:center}
|
||||
.search input{
|
||||
font-family:var(--mono);font-size:13px;
|
||||
padding:9px 14px 9px 34px;width:260px;
|
||||
border:1px solid var(--rule);border-radius:999px;
|
||||
background:var(--card);color:var(--ink);
|
||||
}
|
||||
.search input::placeholder{color:#93A3AE}
|
||||
.search svg{position:absolute;left:12px;width:14px;height:14px;stroke:var(--ink-soft);fill:none;stroke-width:2}
|
||||
.count{font-family:var(--mono);font-size:12px;color:var(--ink-soft);white-space:nowrap}
|
||||
|
||||
/* ── hero ───────────────────────────────────── */
|
||||
.hero{padding:88px 0 64px;border-bottom:1px solid var(--rule)}
|
||||
.eyebrow{
|
||||
font-family:var(--mono);font-size:12px;letter-spacing:.16em;
|
||||
text-transform:uppercase;color:var(--ink-soft);margin:0 0 26px
|
||||
}
|
||||
.title{
|
||||
font-family:var(--sans);
|
||||
font-size:clamp(3rem,10vw,7.5rem);
|
||||
font-weight:800;line-height:.86;letter-spacing:-.045em;
|
||||
margin:0;
|
||||
}
|
||||
.title .arrow{color:var(--fuchsia);display:inline-block;padding:0 .06em}
|
||||
.title .go{color:var(--go-deep)}
|
||||
.deck{
|
||||
max-width:38ch;margin:28px 0 0;font-size:1.15rem;color:var(--ink-soft);
|
||||
font-weight:400;line-height:1.45
|
||||
}
|
||||
|
||||
/* live rotating pair */
|
||||
.demo{
|
||||
margin-top:46px;background:var(--card);border:1px solid var(--rule);
|
||||
border-radius:14px;overflow:hidden;max-width:820px;
|
||||
box-shadow:0 1px 0 rgba(11,18,21,.04),0 14px 34px -26px rgba(11,18,21,.5)
|
||||
}
|
||||
.demo-row{display:grid;grid-template-columns:1fr 52px 1fr;align-items:stretch}
|
||||
.demo-cell{padding:26px 22px;display:flex;align-items:center;min-height:96px}
|
||||
.demo-cell code{font-family:var(--mono);font-size:.92rem;line-height:1.6;white-space:pre-wrap}
|
||||
.demo-mid{
|
||||
display:grid;place-items:center;border-left:1px solid var(--rule);
|
||||
border-right:1px solid var(--rule);color:var(--go);font-size:1.5rem;
|
||||
font-family:var(--mono);background:#F6F9FB
|
||||
}
|
||||
.demo-cell.js{border-top:3px solid var(--js)}
|
||||
.demo-cell.go{border-top:3px solid var(--go)}
|
||||
.fade{transition:opacity .45s ease}
|
||||
.fade.out{opacity:0}
|
||||
|
||||
/* contents */
|
||||
.contents{margin-top:52px}
|
||||
.contents h2{
|
||||
font-family:var(--mono);font-size:12px;letter-spacing:.16em;text-transform:uppercase;
|
||||
color:var(--ink-soft);font-weight:500;margin:0 0 14px
|
||||
}
|
||||
.chips{display:flex;flex-wrap:wrap;gap:8px;padding:0;margin:0;list-style:none}
|
||||
.chips a{
|
||||
display:inline-block;font-family:var(--mono);font-size:12.5px;
|
||||
padding:6px 12px;border:1px solid var(--rule);border-radius:999px;
|
||||
background:var(--card);color:var(--ink);text-decoration:none;
|
||||
transition:border-color .15s,color .15s
|
||||
}
|
||||
.chips a:hover{border-color:var(--go);color:var(--go-deep)}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<style>
|
||||
/* ── entries ────────────────────────────────── */
|
||||
.entries{padding:0 0 120px}
|
||||
.entry{padding:56px 0;border-bottom:1px solid var(--rule)}
|
||||
.entry[hidden]{display:none}
|
||||
.entry-head{display:flex;align-items:baseline;gap:14px;flex-wrap:wrap;margin-bottom:22px}
|
||||
.entry-head h3{
|
||||
font-size:1.5rem;font-weight:700;letter-spacing:-.02em;margin:0;line-height:1.15
|
||||
}
|
||||
.entry-head .tag{
|
||||
font-family:var(--mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;
|
||||
color:var(--ink-soft);border:1px solid var(--rule);border-radius:999px;padding:3px 9px;
|
||||
background:var(--card)
|
||||
}
|
||||
.pair{
|
||||
display:grid;grid-template-columns:1fr 56px 1fr;align-items:stretch;
|
||||
background:var(--card);border:1px solid var(--rule);border-radius:14px;overflow:hidden;
|
||||
box-shadow:0 1px 0 rgba(11,18,21,.03)
|
||||
}
|
||||
.side{padding:20px 22px 22px;min-width:0}
|
||||
.side.js{border-top:3px solid var(--js)}
|
||||
.side.go{border-top:3px solid var(--go)}
|
||||
.side .lang{
|
||||
font-family:var(--mono);font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;
|
||||
color:var(--ink-soft);margin:0 0 12px;display:block
|
||||
}
|
||||
.side pre{margin:0;overflow-x:auto}
|
||||
.side code{
|
||||
font-family:var(--mono);font-size:.845rem;line-height:1.65;
|
||||
white-space:pre;display:block;tab-size:4
|
||||
}
|
||||
.mid{
|
||||
display:grid;place-items:center;background:#F6F9FB;
|
||||
border-left:1px solid var(--rule);border-right:1px solid var(--rule);
|
||||
color:var(--go);font-family:var(--mono);font-size:1.25rem;user-select:none
|
||||
}
|
||||
.note{
|
||||
margin:18px 0 0;max-width:74ch;color:var(--ink-soft);font-size:1.02rem;line-height:1.55
|
||||
}
|
||||
.note b{color:var(--ink);font-weight:500}
|
||||
.note code{
|
||||
font-family:var(--mono);font-size:.86em;background:#DDE6EC;
|
||||
padding:1px 5px;border-radius:4px;color:var(--ink)
|
||||
}
|
||||
|
||||
/* token colours */
|
||||
.tk{color:var(--fuchsia)} /* keyword */
|
||||
.ts{color:var(--teal)} /* literal */
|
||||
.tf{color:var(--go-deep)} /* call */
|
||||
.tc{color:#8A97A3;font-style:italic} /* comment */
|
||||
|
||||
/* ── tooling table ──────────────────────────── */
|
||||
.tooling{padding:56px 0 0}
|
||||
.tooling h3{font-size:1.5rem;font-weight:700;letter-spacing:-.02em;margin:0 0 22px}
|
||||
table{
|
||||
width:100%;border-collapse:collapse;background:var(--card);
|
||||
border:1px solid var(--rule);border-radius:14px;overflow:hidden;
|
||||
font-family:var(--mono);font-size:.85rem
|
||||
}
|
||||
th{
|
||||
text-align:left;padding:14px 20px;font-size:10.5px;letter-spacing:.16em;
|
||||
text-transform:uppercase;color:var(--ink-soft);font-weight:500;
|
||||
border-bottom:1px solid var(--rule)
|
||||
}
|
||||
th:first-child{box-shadow:inset 0 3px 0 var(--js)}
|
||||
th:last-child{box-shadow:inset 0 3px 0 var(--go)}
|
||||
td{padding:12px 20px;border-bottom:1px solid #EDF2F5;vertical-align:top}
|
||||
tr:last-child td{border-bottom:none}
|
||||
td:first-child{width:42%;color:var(--ink-soft)}
|
||||
|
||||
/* ── empty state ────────────────────────────── */
|
||||
.empty{
|
||||
display:none;padding:80px 0;text-align:center;font-size:1.1rem;color:var(--ink-soft)
|
||||
}
|
||||
.empty.on{display:block}
|
||||
.empty span{font-family:var(--mono);color:var(--ink)}
|
||||
|
||||
footer{
|
||||
padding:44px 0 80px;border-top:1px solid var(--rule);
|
||||
font-family:var(--mono);font-size:12px;color:var(--ink-soft);line-height:1.8
|
||||
}
|
||||
|
||||
/* ── responsive ─────────────────────────────── */
|
||||
@media (max-width:880px){
|
||||
.pair,.demo-row{grid-template-columns:1fr}
|
||||
.mid,.demo-mid{
|
||||
border-left:none;border-right:none;
|
||||
border-top:1px solid var(--rule);border-bottom:1px solid var(--rule);
|
||||
padding:8px 0
|
||||
}
|
||||
.mid span,.demo-mid span{display:inline-block;transform:rotate(90deg)}
|
||||
.side.go,.demo-cell.go{border-top:none}
|
||||
.search input{width:150px}
|
||||
.deck{font-size:1.05rem}
|
||||
}
|
||||
@media (max-width:560px){
|
||||
.bar-in{height:58px;gap:12px}
|
||||
.count{display:none}
|
||||
.hero{padding:56px 0 44px}
|
||||
}
|
||||
@media (prefers-reduced-motion:reduce){
|
||||
html{scroll-behavior:auto}
|
||||
.fade{transition:none}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="bar">
|
||||
<div class="wrap bar-in">
|
||||
<a class="mark" href="#top">JS <em>→</em> <b>GO</b></a>
|
||||
<span class="count" id="count"></span>
|
||||
<div class="search">
|
||||
<svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="M20 20l-4-4"/></svg>
|
||||
<input id="filter" type="search" placeholder="find a construct" aria-label="Filter entries">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main id="top">
|
||||
<section class="hero">
|
||||
<div class="wrap">
|
||||
<p class="eyebrow">A phrasebook for JavaScript developers</p>
|
||||
<h1 class="title">JavaScript<br><span class="arrow">→</span><span class="go">Go</span></h1>
|
||||
<p class="deck">Look up something you already write every day, and read the Go sentence that means the same thing — plus a note on where the translation stops being literal.</p>
|
||||
|
||||
<div class="demo" aria-label="Example translations">
|
||||
<div class="demo-row">
|
||||
<div class="demo-cell js"><code id="demoJs" class="fade" data-lang="js"></code></div>
|
||||
<div class="demo-mid"><span>→</span></div>
|
||||
<div class="demo-cell go"><code id="demoGo" class="fade" data-lang="go"></code></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="contents" aria-label="Contents">
|
||||
<h2>Contents</h2>
|
||||
<ul class="chips" id="chips"></ul>
|
||||
</nav>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="entries wrap" id="entries">
|
||||
<article class="entry" id="entry-point">
|
||||
<div class="entry-head"><h3>Getting a program to run</h3><span class="tag">package main</span></div>
|
||||
<div class="pair">
|
||||
<div class="side js"><span class="lang">JavaScript</span><pre><code data-lang="js">// hello.js — run: node hello.js
|
||||
|
||||
console.log("Hello, world");
|
||||
|
||||
// any file can be the entry point,
|
||||
// and top-level code just runs</code></pre></div>
|
||||
<div class="mid"><span>→</span></div>
|
||||
<div class="side go"><span class="lang">Go</span><pre><code data-lang="go">// hello.go — run: go run hello.go
|
||||
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func main() {
|
||||
fmt.Println("Hello, world")
|
||||
}</code></pre></div>
|
||||
</div>
|
||||
<p class="note">Every Go file belongs to a package. Only <code>package main</code> with a <code>func main()</code> builds into a runnable program. There is no top-level code — statements live inside functions.</p>
|
||||
</article>
|
||||
|
||||
<article class="entry" id="variables">
|
||||
<div class="entry-head"><h3>Declaring variables</h3><span class="tag">:= and var</span></div>
|
||||
<div class="pair">
|
||||
<div class="side js"><span class="lang">JavaScript</span><pre><code data-lang="js">let count = 1;
|
||||
count = 2;
|
||||
|
||||
const name = "ada";
|
||||
|
||||
let empty; // undefined
|
||||
var old = true; // avoid</code></pre></div>
|
||||
<div class="mid"><span>→</span></div>
|
||||
<div class="side go"><span class="lang">Go</span><pre><code data-lang="go">count := 1 // inside a function
|
||||
count = 2
|
||||
|
||||
const name = "ada"
|
||||
|
||||
var empty string // "" — the zero value
|
||||
var n int // 0
|
||||
var ok bool // false</code></pre></div>
|
||||
</div>
|
||||
<p class="note"><code>:=</code> declares and infers the type in one step, but only inside a function; at package level use <code>var</code>. There is no <b>undefined</b> — every variable starts at its type's zero value. A declared local you never read is a compile error, not a warning.</p>
|
||||
</article>
|
||||
|
||||
<article class="entry" id="types">
|
||||
<div class="entry-head"><h3>Types and conversion</h3><span class="tag">strconv</span></div>
|
||||
<div class="pair">
|
||||
<div class="side js"><span class="lang">JavaScript</span><pre><code data-lang="js">typeof 42; // "number"
|
||||
|
||||
Number("42"); // 42
|
||||
String(42); // "42"
|
||||
parseInt("42", 10); // 42
|
||||
|
||||
(42).toFixed(2); // "42.00"
|
||||
1 / 2; // 0.5</code></pre></div>
|
||||
<div class="mid"><span>→</span></div>
|
||||
<div class="side go"><span class="lang">Go</span><pre><code data-lang="go">reflect.TypeOf(42) // int
|
||||
|
||||
n, err := strconv.Atoi("42")
|
||||
s := strconv.Itoa(42)
|
||||
f, err := strconv.ParseFloat("4.2", 64)
|
||||
|
||||
fmt.Sprintf("%.2f", 42.0) // "42.00"
|
||||
1 / 2 // 0 — integer division
|
||||
float64(1) / 2 // 0.5</code></pre></div>
|
||||
</div>
|
||||
<p class="note">One <code>number</code> becomes <code>int</code>, <code>int64</code>, <code>float64</code> and friends. Conversion is always explicit — <code>float64(i)</code>, <code>int(f)</code> — and never happens behind your back, so mixing an <code>int</code> and a <code>float64</code> in one expression will not compile. <code>int(2.9)</code> truncates to 2. Parsing returns a value <b>and</b> an error.</p>
|
||||
</article>
|
||||
|
||||
<article class="entry" id="strings">
|
||||
<div class="entry-head"><h3>Working with strings</h3><span class="tag">strings, fmt</span></div>
|
||||
<div class="pair">
|
||||
<div class="side js"><span class="lang">JavaScript</span><pre><code data-lang="js">const who = "world";
|
||||
`Hello, ${who}!`;
|
||||
|
||||
"abc".toUpperCase();
|
||||
"a,b".split(",");
|
||||
["a", "b"].join("-");
|
||||
"abc".includes("b");
|
||||
"abc".trim().replace("a", "z");
|
||||
|
||||
"héllo".length; // 5</code></pre></div>
|
||||
<div class="mid"><span>→</span></div>
|
||||
<div class="side go"><span class="lang">Go</span><pre><code data-lang="go">who := "world"
|
||||
fmt.Sprintf("Hello, %s!", who)
|
||||
|
||||
strings.ToUpper("abc")
|
||||
strings.Split("a,b", ",")
|
||||
strings.Join([]string{"a", "b"}, "-")
|
||||
strings.Contains("abc", "b")
|
||||
strings.ReplaceAll(strings.TrimSpace(s), "a", "z")
|
||||
|
||||
len("héllo") // 6 bytes
|
||||
utf8.RuneCountInString("héllo") // 5</code></pre></div>
|
||||
</div>
|
||||
<p class="note">Strings are immutable UTF-8 <b>bytes</b>. <code>len</code> counts bytes; ranging over a string yields runes (code points) with their byte offsets. There are no methods on strings — the verbs live in the <code>strings</code> package. Building a string in a loop wants <code>strings.Builder</code>, not <code>+=</code>.</p>
|
||||
</article>
|
||||
|
||||
<article class="entry" id="lists">
|
||||
<div class="entry-head"><h3>Lists</h3><span class="tag">slices</span></div>
|
||||
<div class="pair">
|
||||
<div class="side js"><span class="lang">JavaScript</span><pre><code data-lang="js">const xs = [1, 2, 3];
|
||||
|
||||
xs.push(4);
|
||||
xs.length;
|
||||
xs[0];
|
||||
xs[1] = 9;
|
||||
|
||||
xs.slice(1, 3);
|
||||
const ys = [...xs];
|
||||
xs.concat(ys);</code></pre></div>
|
||||
<div class="mid"><span>→</span></div>
|
||||
<div class="side go"><span class="lang">Go</span><pre><code data-lang="go">xs := []int{1, 2, 3}
|
||||
|
||||
xs = append(xs, 4) // reassign!
|
||||
len(xs)
|
||||
xs[0]
|
||||
xs[1] = 9
|
||||
|
||||
xs[1:3] // a view, shares memory
|
||||
ys := make([]int, len(xs))
|
||||
copy(ys, xs) // a real copy
|
||||
append(xs, ys...)</code></pre></div>
|
||||
</div>
|
||||
<p class="note"><code>append</code> returns a new slice header, so you must assign the result back. Slicing does not copy: <code>xs[1:3]</code> looks into the same underlying array, and writing through it changes the original. <code>[3]int</code> is a fixed-size array and a genuinely different type from the slice <code>[]int</code>.</p>
|
||||
</article>
|
||||
|
||||
<article class="entry" id="iteration">
|
||||
<div class="entry-head"><h3>map, filter, reduce</h3><span class="tag">write the loop</span></div>
|
||||
<div class="pair">
|
||||
<div class="side js"><span class="lang">JavaScript</span><pre><code data-lang="js">xs.map(x => x * 2);
|
||||
|
||||
xs.filter(x => x > 1);
|
||||
|
||||
xs.reduce((a, b) => a + b, 0);
|
||||
|
||||
xs.includes(2);
|
||||
xs.indexOf(2);
|
||||
xs.sort((a, b) => a - b);</code></pre></div>
|
||||
<div class="mid"><span>→</span></div>
|
||||
<div class="side go"><span class="lang">Go</span><pre><code data-lang="go">out := make([]int, 0, len(xs))
|
||||
for _, x := range xs {
|
||||
out = append(out, x*2)
|
||||
}
|
||||
|
||||
sum := 0
|
||||
for _, x := range xs {
|
||||
sum += x
|
||||
}
|
||||
|
||||
slices.Contains(xs, 2)
|
||||
slices.Index(xs, 2)
|
||||
slices.Sort(xs)</code></pre></div>
|
||||
</div>
|
||||
<p class="note">There is no built-in <code>map</code>/<code>filter</code>/<code>reduce</code>, and idiomatic Go writes the loop rather than reaching for a helper. What generics did add is the <code>slices</code> and <code>maps</code> packages, which cover sorting, searching, comparing and cloning.</p>
|
||||
</article>
|
||||
|
||||
<article class="entry" id="maps">
|
||||
<div class="entry-head"><h3>Key–value lookup</h3><span class="tag">map[K]V</span></div>
|
||||
<div class="pair">
|
||||
<div class="side js"><span class="lang">JavaScript</span><pre><code data-lang="js">const ages = { ada: 36 };
|
||||
|
||||
ages.ada;
|
||||
ages["ada"];
|
||||
ages.grace = 45;
|
||||
delete ages.ada;
|
||||
"ada" in ages;
|
||||
Object.keys(ages);
|
||||
|
||||
const m = new Map();
|
||||
m.set("k", 1);</code></pre></div>
|
||||
<div class="mid"><span>→</span></div>
|
||||
<div class="side go"><span class="lang">Go</span><pre><code data-lang="go">ages := map[string]int{"ada": 36}
|
||||
|
||||
ages["ada"]
|
||||
v, ok := ages["ada"] // ok reports presence
|
||||
ages["grace"] = 45
|
||||
delete(ages, "ada")
|
||||
len(ages)
|
||||
|
||||
m := make(map[string]int)
|
||||
m["k"] = 1 // nil map would panic</code></pre></div>
|
||||
</div>
|
||||
<p class="note">Reading a missing key returns the <b>zero value</b>, not <code>undefined</code>, so <code>ages["nobody"]</code> is <code>0</code>. The comma-ok form is how you tell "absent" from "present and zero". Iteration order is deliberately randomised, and a <code>nil</code> map is fine to read but panics on write — <code>make</code> it first.</p>
|
||||
</article>
|
||||
|
||||
<article class="entry" id="structs">
|
||||
<div class="entry-head"><h3>Objects with a shape</h3><span class="tag">struct</span></div>
|
||||
<div class="pair">
|
||||
<div class="side js"><span class="lang">JavaScript</span><pre><code data-lang="js">const user = {
|
||||
name: "ada",
|
||||
age: 36,
|
||||
};
|
||||
|
||||
user.name;
|
||||
|
||||
JSON.stringify(user);
|
||||
const back = JSON.parse(text);</code></pre></div>
|
||||
<div class="mid"><span>→</span></div>
|
||||
<div class="side go"><span class="lang">Go</span><pre><code data-lang="go">type User struct {
|
||||
Name string `json:"name"`
|
||||
Age int `json:"age"`
|
||||
}
|
||||
|
||||
u := User{Name: "ada", Age: 36}
|
||||
u.Name
|
||||
|
||||
b, err := json.Marshal(u)
|
||||
err = json.Unmarshal(text, &back)</code></pre></div>
|
||||
</div>
|
||||
<p class="note">The struct is the everyday object: fixed fields, fixed types, checked at compile time. Tags in backticks control JSON names. A field is visible outside its package — and to <code>encoding/json</code> — only if it starts with a <b>capital letter</b>, which is the single most common reason a struct marshals to <code>{}</code>.</p>
|
||||
</article>
|
||||
|
||||
<article class="entry" id="functions">
|
||||
<div class="entry-head"><h3>Functions</h3><span class="tag">multiple returns</span></div>
|
||||
<div class="pair">
|
||||
<div class="side js"><span class="lang">JavaScript</span><pre><code data-lang="js">function add(a, b) { return a + b; }
|
||||
const add2 = (a, b) => a + b;
|
||||
|
||||
function greet(name = "you") {}
|
||||
function sum(...nums) {}
|
||||
|
||||
const { a, b } = pair();
|
||||
|
||||
const twice = f => x => f(f(x));</code></pre></div>
|
||||
<div class="mid"><span>→</span></div>
|
||||
<div class="side go"><span class="lang">Go</span><pre><code data-lang="go">func add(a, b int) int { return a + b }
|
||||
add2 := func(a, b int) int { return a + b }
|
||||
|
||||
// no default arguments — use an options
|
||||
// struct or a second constructor
|
||||
func sum(nums ...int) int { ... }
|
||||
|
||||
a, b := pair() // two return values
|
||||
|
||||
func twice(f func(int) int) func(int) int { ... }</code></pre></div>
|
||||
</div>
|
||||
<p class="note">No default or named parameters; the usual answers are a config struct or variadic option functions. Returning several values is native, and that is how errors travel. <code>defer f.Close()</code> schedules cleanup to run when the function exits, whichever way it exits.</p>
|
||||
</article>
|
||||
<article class="entry" id="pointers">
|
||||
<div class="entry-head"><h3>Copies and pointers</h3><span class="tag">& and *</span></div>
|
||||
<div class="pair">
|
||||
<div class="side js"><span class="lang">JavaScript</span><pre><code data-lang="js">// the engine decides for you:
|
||||
// objects by reference, primitives by value
|
||||
|
||||
function rename(u) { u.name = "new"; }
|
||||
rename(user); // user is changed
|
||||
|
||||
let n = 1;
|
||||
function inc(x) { x++; }
|
||||
inc(n); // n is still 1</code></pre></div>
|
||||
<div class="mid"><span>→</span></div>
|
||||
<div class="side go"><span class="lang">Go</span><pre><code data-lang="go">// everything is passed by value.
|
||||
// you choose when to pass an address.
|
||||
|
||||
func rename(u *User) { u.Name = "new" }
|
||||
rename(&u) // u is changed
|
||||
|
||||
func inc(x *int) { *x++ }
|
||||
inc(&n) // n is now 2
|
||||
|
||||
p := &u
|
||||
p.Name = "ada" // auto-dereferenced</code></pre></div>
|
||||
</div>
|
||||
<p class="note">A struct argument is a <b>copy</b> unless you pass a pointer, which you do when the function must mutate the original or the value is large. Slices, maps and channels already hold an internal reference, so they behave the way you expect. There is no pointer arithmetic and there is a garbage collector: this is only <code>&</code> and <code>*</code>.</p>
|
||||
</article>
|
||||
|
||||
<article class="entry" id="control-flow">
|
||||
<div class="entry-head"><h3>Branches and loops</h3><span class="tag">one keyword: for</span></div>
|
||||
<div class="pair">
|
||||
<div class="side js"><span class="lang">JavaScript</span><pre><code data-lang="js">if (x > 1) {} else if (y) {} else {}
|
||||
|
||||
for (let i = 0; i < 10; i++) {}
|
||||
while (ok) {}
|
||||
do {} while (ok);
|
||||
|
||||
for (const x of xs) {}
|
||||
for (const k in obj) {}
|
||||
|
||||
const size = x > 1 ? "big" : "small";</code></pre></div>
|
||||
<div class="mid"><span>→</span></div>
|
||||
<div class="side go"><span class="lang">Go</span><pre><code data-lang="go">if x > 1 { } else if y { } else { }
|
||||
if v, err := f(); err != nil { } // scoped init
|
||||
|
||||
for i := 0; i < 10; i++ { }
|
||||
for ok { } // while
|
||||
for { break } // infinite
|
||||
|
||||
for i, x := range xs { }
|
||||
for k, v := range m { }
|
||||
|
||||
// no ternary — write the if</code></pre></div>
|
||||
</div>
|
||||
<p class="note"><code>for</code> is the only loop keyword and covers all four shapes. Conditions take no parentheses, braces are never optional, and the opening brace must sit on the same line. The scoped init form — <code>if v, err := f(); err != nil</code> — keeps <code>v</code> and <code>err</code> from leaking into the surrounding scope.</p>
|
||||
</article>
|
||||
|
||||
<article class="entry" id="switch">
|
||||
<div class="entry-head"><h3>switch</h3><span class="tag">no break needed</span></div>
|
||||
<div class="pair">
|
||||
<div class="side js"><span class="lang">JavaScript</span><pre><code data-lang="js">switch (x) {
|
||||
case 1:
|
||||
one();
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
few();
|
||||
break;
|
||||
default:
|
||||
other();
|
||||
}</code></pre></div>
|
||||
<div class="mid"><span>→</span></div>
|
||||
<div class="side go"><span class="lang">Go</span><pre><code data-lang="go">switch x {
|
||||
case 1:
|
||||
one()
|
||||
case 2, 3:
|
||||
few()
|
||||
default:
|
||||
other()
|
||||
}
|
||||
|
||||
switch { // no subject:
|
||||
case x > 10: // an if/else chain
|
||||
big()
|
||||
}</code></pre></div>
|
||||
</div>
|
||||
<p class="note">Cases break on their own; falling through is opt-in with the <code>fallthrough</code> keyword. One case can list several values, a case can carry an <code>init</code> statement, and a subjectless <code>switch</code> is the idiomatic replacement for a long if/else ladder.</p>
|
||||
</article>
|
||||
|
||||
<article class="entry" id="equality">
|
||||
<div class="entry-head"><h3>Equality and truthiness</h3><span class="tag">no coercion</span></div>
|
||||
<div class="pair">
|
||||
<div class="side js"><span class="lang">JavaScript</span><pre><code data-lang="js">1 == "1"; // true
|
||||
1 === "1"; // false
|
||||
|
||||
if (list.length) {}
|
||||
if (str) {}
|
||||
if (!user) {}
|
||||
|
||||
value ?? fallback
|
||||
user?.address?.city</code></pre></div>
|
||||
<div class="mid"><span>→</span></div>
|
||||
<div class="side go"><span class="lang">Go</span><pre><code data-lang="go">// == is always strict.
|
||||
// comparing different types won't compile.
|
||||
|
||||
if len(list) > 0 { }
|
||||
if str != "" { }
|
||||
if user == nil { }
|
||||
|
||||
// no ?? and no ?. — check it
|
||||
if v, ok := m[k]; ok { use(v) }
|
||||
if u != nil && u.Address != nil { }</code></pre></div>
|
||||
</div>
|
||||
<p class="note">There is no truthiness: <code>if</code> takes a <code>bool</code> and nothing else, so every check is spelled out. Structs and arrays compare with <code>==</code> field by field; slices, maps and functions can only be compared against <code>nil</code>, and <code>reflect.DeepEqual</code> or <code>slices.Equal</code> handles the rest.</p>
|
||||
</article>
|
||||
|
||||
<article class="entry" id="errors">
|
||||
<div class="entry-head"><h3>Things going wrong</h3><span class="tag">errors are values</span></div>
|
||||
<div class="pair">
|
||||
<div class="side js"><span class="lang">JavaScript</span><pre><code data-lang="js">try {
|
||||
const data = risky();
|
||||
use(data);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
throw new Error("loading failed");
|
||||
} finally {
|
||||
cleanup();
|
||||
}</code></pre></div>
|
||||
<div class="mid"><span>→</span></div>
|
||||
<div class="side go"><span class="lang">Go</span><pre><code data-lang="go">defer cleanup()
|
||||
|
||||
data, err := risky()
|
||||
if err != nil {
|
||||
return fmt.Errorf("loading: %w", err)
|
||||
}
|
||||
use(data)
|
||||
|
||||
errors.New("boom")
|
||||
errors.Is(err, os.ErrNotExist)
|
||||
panic("unrecoverable") // rare, not control flow</code></pre></div>
|
||||
</div>
|
||||
<p class="note">Nothing is thrown. An error is an ordinary value returned next to the result, and the <code>if err != nil</code> block you write every few lines <b>is</b> the idiom, not a sign you are doing it wrong. <code>%w</code> wraps an error so <code>errors.Is</code> and <code>errors.As</code> can look through the chain later.</p>
|
||||
</article>
|
||||
|
||||
<article class="entry" id="classes">
|
||||
<div class="entry-head"><h3>Classes</h3><span class="tag">methods and embedding</span></div>
|
||||
<div class="pair">
|
||||
<div class="side js"><span class="lang">JavaScript</span><pre><code data-lang="js">class Animal {
|
||||
constructor(name) { this.name = name; }
|
||||
speak() { return `${this.name} makes a sound`; }
|
||||
}
|
||||
|
||||
class Dog extends Animal {
|
||||
speak() { return `${this.name} barks`; }
|
||||
}
|
||||
|
||||
new Dog("rex").speak();</code></pre></div>
|
||||
<div class="mid"><span>→</span></div>
|
||||
<div class="side go"><span class="lang">Go</span><pre><code data-lang="go">type Animal struct{ Name string }
|
||||
|
||||
func NewAnimal(name string) *Animal {
|
||||
return &Animal{Name: name}
|
||||
}
|
||||
|
||||
func (a *Animal) Speak() string {
|
||||
return a.Name + " makes a sound"
|
||||
}
|
||||
|
||||
type Dog struct{ Animal } // embedding
|
||||
|
||||
func (d *Dog) Speak() string {
|
||||
return d.Name + " barks"
|
||||
}</code></pre></div>
|
||||
</div>
|
||||
<p class="note">No classes, no <code>new</code> keyword for your own types, no inheritance. A method is a function with a receiver, and the receiver replaces <code>this</code> — you name it yourself, and it is a pointer whenever the method mutates. Embedding promotes the inner type's fields and methods onto the outer one: composition, not a parent. A constructor is just a function called <code>NewDog</code>.</p>
|
||||
</article>
|
||||
|
||||
<article class="entry" id="interfaces">
|
||||
<div class="entry-head"><h3>Duck typing</h3><span class="tag">implicit interfaces</span></div>
|
||||
<div class="pair">
|
||||
<div class="side js"><span class="lang">JavaScript</span><pre><code data-lang="js">// anything with .speak() will do,
|
||||
// and you find out at runtime
|
||||
|
||||
function speakAll(items) {
|
||||
for (const i of items) {
|
||||
console.log(i.speak());
|
||||
}
|
||||
}
|
||||
|
||||
if (x instanceof Dog) {}</code></pre></div>
|
||||
<div class="mid"><span>→</span></div>
|
||||
<div class="side go"><span class="lang">Go</span><pre><code data-lang="go">type Speaker interface {
|
||||
Speak() string
|
||||
}
|
||||
|
||||
func speakAll(items []Speaker) {
|
||||
for _, i := range items {
|
||||
fmt.Println(i.Speak())
|
||||
}
|
||||
}
|
||||
|
||||
if d, ok := x.(*Dog); ok { use(d) }</code></pre></div>
|
||||
</div>
|
||||
<p class="note">There is no <code>implements</code>. A type satisfies an interface simply by having the methods, which means you can write an interface for someone else's type after the fact. Keep them small — <code>io.Reader</code> is one method. <code>any</code> holds anything, and you get the concrete type back with an assertion or a <code>switch v := x.(type)</code>.</p>
|
||||
</article>
|
||||
|
||||
<article class="entry" id="modules">
|
||||
<div class="entry-head"><h3>Modules and visibility</h3><span class="tag">go.mod</span></div>
|
||||
<div class="pair">
|
||||
<div class="side js"><span class="lang">JavaScript</span><pre><code data-lang="js">// greet.js
|
||||
export function hello() {}
|
||||
export default thing;
|
||||
|
||||
// app.js
|
||||
import { hello } from "./greet.js";
|
||||
import thing from "some-pkg";
|
||||
|
||||
// package.json, node_modules/</code></pre></div>
|
||||
<div class="mid"><span>→</span></div>
|
||||
<div class="side go"><span class="lang">Go</span><pre><code data-lang="go">// greet/greet.go
|
||||
package greet
|
||||
|
||||
func Hello() {} // exported: capital H
|
||||
func local() {} // package-private
|
||||
|
||||
// main.go
|
||||
import (
|
||||
"fmt"
|
||||
"example.com/app/greet"
|
||||
)
|
||||
|
||||
// go.mod, shared module cache</code></pre></div>
|
||||
</div>
|
||||
<p class="note">Visibility is spelled with a capital letter rather than an <code>export</code> keyword, so renaming <code>hello</code> to <code>Hello</code> publishes it. A directory is a package and its import path is the module path plus that directory. Unused imports fail the build, which is why everyone runs <code>goimports</code> on save.</p>
|
||||
</article>
|
||||
|
||||
<article class="entry" id="async">
|
||||
<div class="entry-head"><h3>Doing things at the same time</h3><span class="tag">goroutines</span></div>
|
||||
<div class="pair">
|
||||
<div class="side js"><span class="lang">JavaScript</span><pre><code data-lang="js">async function load() {
|
||||
const a = await fetchA();
|
||||
return a;
|
||||
}
|
||||
|
||||
const [x, y] = await Promise.all([p1(), p2()]);
|
||||
|
||||
setTimeout(fn, 1000);</code></pre></div>
|
||||
<div class="mid"><span>→</span></div>
|
||||
<div class="side go"><span class="lang">Go</span><pre><code data-lang="go">ch := make(chan string)
|
||||
go func() { ch <- fetchA() }()
|
||||
a := <-ch // blocks until ready
|
||||
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
go func() { defer wg.Done(); p1() }()
|
||||
go func() { defer wg.Done(); p2() }()
|
||||
wg.Wait()
|
||||
|
||||
time.Sleep(time.Second)</code></pre></div>
|
||||
</div>
|
||||
<p class="note">No event loop, and no coloured functions: any ordinary function becomes concurrent by putting <code>go</code> in front of the call. Channels move values between goroutines, and an unbuffered send blocks until someone receives — that blocking is the synchronisation. If you would rather share memory, take a <code>sync.Mutex</code>. Nothing waits for your goroutines when <code>main</code> returns.</p>
|
||||
</article>
|
||||
|
||||
<article class="entry" id="cancellation">
|
||||
<div class="entry-head"><h3>Racing and cancelling</h3><span class="tag">select, context</span></div>
|
||||
<div class="pair">
|
||||
<div class="side js"><span class="lang">JavaScript</span><pre><code data-lang="js">await Promise.race([work(), timeout(1000)]);
|
||||
|
||||
const c = new AbortController();
|
||||
fetch(url, { signal: c.signal });
|
||||
c.abort();</code></pre></div>
|
||||
<div class="mid"><span>→</span></div>
|
||||
<div class="side go"><span class="lang">Go</span><pre><code data-lang="go">select {
|
||||
case v := <-work:
|
||||
use(v)
|
||||
case <-time.After(time.Second):
|
||||
return errTimeout
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Second)
|
||||
defer cancel()
|
||||
req = req.WithContext(ctx)</code></pre></div>
|
||||
</div>
|
||||
<p class="note"><code>select</code> waits on several channel operations and proceeds with whichever is ready first, so it covers both <code>Promise.race</code> and a non-blocking poll (with a <code>default</code> case). <code>context</code> carries deadlines and cancellation down a call chain and is, by convention, the first parameter of anything that blocks or touches the network.</p>
|
||||
</article>
|
||||
|
||||
<article class="entry" id="tests">
|
||||
<div class="entry-head"><h3>Tests</h3><span class="tag">go test</span></div>
|
||||
<div class="pair">
|
||||
<div class="side js"><span class="lang">JavaScript</span><pre><code data-lang="js">// add.test.js
|
||||
import { test, expect } from "vitest";
|
||||
|
||||
test("adds", () => {
|
||||
expect(add(1, 2)).toBe(3);
|
||||
});
|
||||
|
||||
// npx vitest</code></pre></div>
|
||||
<div class="mid"><span>→</span></div>
|
||||
<div class="side go"><span class="lang">Go</span><pre><code data-lang="go">// add_test.go
|
||||
package math
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestAdd(t *testing.T) {
|
||||
if got := add(1, 2); got != 3 {
|
||||
t.Errorf("add(1, 2) = %d, want 3", got)
|
||||
}
|
||||
}
|
||||
|
||||
// go test ./...</code></pre></div>
|
||||
</div>
|
||||
<p class="note">The runner ships with the toolchain: no framework, no config, no dependency. Files end in <code>_test.go</code>, functions start with <code>Test</code> and take <code>*testing.T</code>. There are no assertion helpers on purpose — you compare values and call <code>t.Errorf</code> with a message that says what you got and what you wanted.</p>
|
||||
</article>
|
||||
</section>
|
||||
|
||||
<section class="wrap tooling" id="tooling">
|
||||
<h3>The rest of the toolbox</h3>
|
||||
<table>
|
||||
<thead><tr><th>JavaScript</th><th>Go</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>npm install</td><td>go get · go mod tidy</td></tr>
|
||||
<tr><td>package.json</td><td>go.mod</td></tr>
|
||||
<tr><td>node_modules/</td><td>a shared module cache</td></tr>
|
||||
<tr><td>npm run build</td><td>go build ./...</td></tr>
|
||||
<tr><td>node app.js</td><td>go run .</td></tr>
|
||||
<tr><td>prettier</td><td>gofmt — built in, and not configurable</td></tr>
|
||||
<tr><td>eslint</td><td>go vet · staticcheck</td></tr>
|
||||
<tr><td>jest · vitest</td><td>go test ./...</td></tr>
|
||||
<tr><td>tsc</td><td>the compiler — types aren't optional</td></tr>
|
||||
<tr><td>nodemon</td><td>air, or just rebuild; it's fast</td></tr>
|
||||
<tr><td>JSDoc</td><td>go doc · pkg.go.dev</td></tr>
|
||||
<tr><td>esbuild + a Dockerfile</td><td>go build — one static binary</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<p class="empty" id="empty">Nothing matches <span id="term"></span>. Try <span>append</span>, <span>goroutine</span> or <span>nil</span>.</p>
|
||||
</main>
|
||||
|
||||
<footer class="wrap">
|
||||
Written against Go 1.22 · tabs are gofmt's doing, not mine<br>
|
||||
Everything here compiles the way it reads, except where the note says otherwise.
|
||||
</footer>
|
||||
<script>
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
/* ── minimal two-language highlighter ─────────────────────── */
|
||||
var KW = {
|
||||
js: /^(const|let|var|function|return|if|else|for|of|in|while|do|switch|case|default|break|continue|new|class|extends|this|try|catch|finally|throw|async|await|import|export|from|typeof|instanceof|delete|null|undefined|true|false)$/,
|
||||
go: /^(package|import|func|var|const|type|struct|interface|map|chan|go|defer|range|select|fallthrough|return|if|else|for|switch|case|default|break|continue|nil|true|false|make|new|len|cap|append|copy|delete|panic|recover|string|int|int64|float64|bool|byte|rune|any|error)$/
|
||||
};
|
||||
var RE = /(\/\/[^\n]*|\/\*[\s\S]*?\*\/)|(`[^`]*`|"(?:\\.|[^"\\\n])*"|'(?:\\.|[^'\\\n])*')|(\b\d+(?:\.\d+)?\b)|([A-Za-z_$][\w$]*)/g;
|
||||
|
||||
function esc(s) {
|
||||
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
||||
}
|
||||
|
||||
function highlight(src, lang) {
|
||||
var kw = KW[lang] || KW.js, out = "", last = 0, m;
|
||||
RE.lastIndex = 0;
|
||||
while ((m = RE.exec(src)) !== null) {
|
||||
out += esc(src.slice(last, m.index));
|
||||
var t = m[0];
|
||||
if (m[1]) out += '<span class="tc">' + esc(t) + "</span>";
|
||||
else if (m[2] || m[3]) out += '<span class="ts">' + esc(t) + "</span>";
|
||||
else if (kw.test(t)) out += '<span class="tk">' + t + "</span>";
|
||||
else if (src.charAt(m.index + t.length) === "(") out += '<span class="tf">' + t + "</span>";
|
||||
else out += esc(t);
|
||||
last = m.index + t.length;
|
||||
}
|
||||
return out + esc(src.slice(last));
|
||||
}
|
||||
|
||||
function paint(el) {
|
||||
el.innerHTML = highlight(el.textContent, el.getAttribute("data-lang"));
|
||||
}
|
||||
|
||||
var blocks = document.querySelectorAll(".side code[data-lang]");
|
||||
for (var i = 0; i < blocks.length; i++) paint(blocks[i]);
|
||||
|
||||
/* ── contents chips + search index ────────────────────────── */
|
||||
var entries = [].slice.call(document.querySelectorAll(".entry"));
|
||||
var chips = document.getElementById("chips");
|
||||
|
||||
entries.forEach(function (entry) {
|
||||
var title = entry.querySelector("h3").textContent;
|
||||
entry.dataset.search = (title + " " + entry.textContent).toLowerCase();
|
||||
|
||||
var li = document.createElement("li");
|
||||
var a = document.createElement("a");
|
||||
a.href = "#" + entry.id;
|
||||
a.textContent = title.toLowerCase();
|
||||
li.appendChild(a);
|
||||
chips.appendChild(li);
|
||||
});
|
||||
|
||||
var toolLi = document.createElement("li");
|
||||
toolLi.innerHTML = '<a href="#tooling">the rest of the toolbox</a>';
|
||||
chips.appendChild(toolLi);
|
||||
|
||||
/* ── filter ───────────────────────────────────────────────── */
|
||||
var input = document.getElementById("filter");
|
||||
var count = document.getElementById("count");
|
||||
var empty = document.getElementById("empty");
|
||||
var term = document.getElementById("term");
|
||||
var tooling = document.getElementById("tooling");
|
||||
|
||||
function apply() {
|
||||
var q = input.value.trim().toLowerCase();
|
||||
var shown = 0;
|
||||
entries.forEach(function (entry) {
|
||||
var hit = !q || entry.dataset.search.indexOf(q) !== -1;
|
||||
entry.hidden = !hit;
|
||||
if (hit) shown++;
|
||||
});
|
||||
tooling.hidden = q.length > 0 && shown === 0;
|
||||
empty.classList.toggle("on", shown === 0);
|
||||
term.textContent = '"' + input.value.trim() + '"';
|
||||
count.textContent = q ? shown + " of " + entries.length : entries.length + " constructs";
|
||||
}
|
||||
|
||||
input.addEventListener("input", apply);
|
||||
apply();
|
||||
|
||||
/* ── hero: one pair at a time ─────────────────────────────── */
|
||||
var pairs = [
|
||||
['const total = 1;', 'total := 1'],
|
||||
['xs.push(4);', 'xs = append(xs, 4)'],
|
||||
['try { risky() }\ncatch (err) { handle(err) }', 'v, err := risky()\nif err != nil { handle(err) }'],
|
||||
['await Promise.all([p1(), p2()]);', 'wg.Wait()'],
|
||||
['class Dog extends Animal {}', 'type Dog struct{ Animal }'],
|
||||
['user?.address?.city', 'if u != nil && u.Address != nil {}'],
|
||||
['xs.map(x => x * 2)', 'for _, x := range xs { ... }']
|
||||
];
|
||||
|
||||
var jsCell = document.getElementById("demoJs");
|
||||
var goCell = document.getElementById("demoGo");
|
||||
var at = 0;
|
||||
|
||||
function show(n) {
|
||||
jsCell.innerHTML = highlight(pairs[n][0], "js");
|
||||
goCell.innerHTML = highlight(pairs[n][1], "go");
|
||||
}
|
||||
show(0);
|
||||
|
||||
var still = window.matchMedia("(prefers-reduced-motion: reduce)");
|
||||
if (!still.matches) {
|
||||
setInterval(function () {
|
||||
jsCell.classList.add("out");
|
||||
goCell.classList.add("out");
|
||||
setTimeout(function () {
|
||||
at = (at + 1) % pairs.length;
|
||||
show(at);
|
||||
jsCell.classList.remove("out");
|
||||
goCell.classList.remove("out");
|
||||
}, 460);
|
||||
}, 3800);
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
1613
_resources/js-to-go_1.html
Normal file
BIN
_resources/kde_desktop app switch.mp4
Normal file
600
_resources/lineageos_device_toplist.txt
Normal file
|
|
@ -0,0 +1,600 @@
|
|||
year devs release device (codename[, type])
|
||||
2024 1 21 Google Pixel 8a ("akita")
|
||||
2023 4 21 Google Pixel Tablet ("tangorpro", tablet)
|
||||
2023 2 21 Sony Xperia 5 V ("pdx237")
|
||||
2023 2 21 Solana Saga ("ingot")
|
||||
2023 2 21 Motorola moto X40 ("rtwo")
|
||||
2023 2 21 Motorola edge+ (2023) ("rtwo")
|
||||
2023 2 21 Motorola edge 40 pro ("rtwo")
|
||||
2023 2 21 Google Pixel 7a ("lynx")
|
||||
2023 1 21 Xiaomi Redmi 12C NFC ("earth")
|
||||
2023 1 21 Xiaomi Redmi 12C ("earth")
|
||||
2023 1 21 Xiaomi POCO C55 ("earth")
|
||||
2023 1 21 Sony Xperia 1 V ("pdx234")
|
||||
2023 1 21 OnePlus 11 5G ("salami")
|
||||
2023 1 21 Google Pixel Fold ("felix", foldable)
|
||||
2023 1 21 Google Pixel 8 Pro ("husky")
|
||||
2023 1 21 Google Pixel 8 ("shiba")
|
||||
2023 1 21 Fairphone 5 ("FP5")
|
||||
2022 6 21 F(x)tec Pro¹ X ("pro1x")
|
||||
2022 3 21 Motorola edge 30 ("dubai")
|
||||
2022 2 21 Motorola moto g52 ("rhode")
|
||||
2022 2 21 Motorola moto g42 ("hawao")
|
||||
2022 2 21 Motorola moto g32 ("devon")
|
||||
2022 2 21 Google Pixel 7 ("panther")
|
||||
2022 1 21 Xiaomi Redmi K60 Pro ("socrates")
|
||||
2022 1 21 Xiaomi Redmi K40S ("munch")
|
||||
2022 1 21 Xiaomi POCO F4 ("munch")
|
||||
2022 1 21 Samsung Galaxy A73 5G ("a73xq")
|
||||
2022 1 21 Realme Q5 ("oscar")
|
||||
2022 1 21 Realme 9 Pro 5G ("oscar")
|
||||
2022 1 21 Realme 9 5G ("oscar")
|
||||
2022 1 21 Realme 10 Pro 5G ("luigi")
|
||||
2022 1 21 Google Pixel 7 Pro ("cheetah")
|
||||
2022 1 21 Google Pixel 6a ("bluejay")
|
||||
2021 8 21 Walmart onn. TV Box 4K (2021) ("dopinder", set top box)
|
||||
2021 8 21 Dynalink TV Box 4K (2021) ("wade", set top box)
|
||||
2021 3 21 Xiaomi Redmi K40 ("alioth")
|
||||
2021 3 21 Xiaomi POCO F3 ("alioth")
|
||||
2021 3 21 Xiaomi Mi 11X ("alioth")
|
||||
2021 3 21 OnePlus 9 Pro ("lemonadep")
|
||||
2021 3 21 OnePlus 9 ("lemonade")
|
||||
2021 3 21 Nintendo Switch OLED [Tablet] ("nx_tab", handheld game console)
|
||||
2021 3 21 Nintendo Switch OLED [Android TV] ("nx", handheld game console)
|
||||
2021 2 21 Xiaomi Redmi Note 10 Pro Max (India) ("sweet")
|
||||
2021 2 21 Xiaomi Redmi Note 10 Pro (India) ("sweet")
|
||||
2021 2 21 Xiaomi Redmi Note 10 Pro ("sweet")
|
||||
2021 2 21 Xiaomi Redmi Note 10 Lite ("miatoll")
|
||||
2021 2 21 Xiaomi Redmi K40 Pro+ ("haydn")
|
||||
2021 2 21 Xiaomi Redmi K40 Pro ("haydn")
|
||||
2021 2 21 Xiaomi Mi 11i ("haydn")
|
||||
2021 2 21 Xiaomi Mi 11X Pro ("haydn")
|
||||
2021 2 21 Xiaomi Mi 10i 5G ("gauguin")
|
||||
2021 2 21 Sony Xperia 5 III ("pdx214")
|
||||
2021 2 21 Motorola moto g200 5G ("xpeng")
|
||||
2021 2 21 Motorola edge 20 pro ("pstar")
|
||||
2021 2 21 Motorola edge 20 ("berlin")
|
||||
2021 2 21 Motorola Edge S30 ("xpeng")
|
||||
2021 1 21 Xiaomi Mi 11 Pro ("mars")
|
||||
2021 1 21 Xiaomi Mi 11 Lite 5G ("renoir")
|
||||
2021 1 21 Xiaomi Mi 11 LE ("lisa")
|
||||
2021 1 21 Xiaomi 11 Lite NE 5G ("lisa")
|
||||
2021 1 21 Xiaomi 11 Lite 5G NE ("lisa")
|
||||
2021 1 21 Sony Xperia 1 III ("pdx215")
|
||||
2021 1 21 Samsung Galaxy M62 ("f62")
|
||||
2021 1 21 Samsung Galaxy M52 5G ("m52xq")
|
||||
2021 1 21 Samsung Galaxy F62 ("f62")
|
||||
2021 1 21 Samsung Galaxy A72 ("a72q")
|
||||
2021 1 21 Samsung Galaxy A52s 5G ("a52sxq")
|
||||
2021 1 21 Samsung Galaxy A52 4G ("a52q")
|
||||
2021 1 21 OnePlus Nord N200 ("dre")
|
||||
2021 1 21 OnePlus 9RT ("martini")
|
||||
2021 1 21 OnePlus 9R ("lemonades")
|
||||
2021 1 21 Motorola moto g30 ("caprip")
|
||||
2021 1 21 Motorola moto g100 ("nio")
|
||||
2021 1 21 Motorola moto g power 2021 ("borneo")
|
||||
2021 1 21 Motorola edge s ("nio")
|
||||
2021 1 21 Motorola edge 2021 ("berlna")
|
||||
2021 1 21 Google Pixel 6 Pro ("raven")
|
||||
2021 1 21 Google Pixel 6 ("oriole")
|
||||
2021 1 21 Google Pixel 5a ("barbet")
|
||||
2021 1 21 Fairphone 4 ("FP4")
|
||||
2020 8 21 Google ADT-3 ("deadpool", set top box)
|
||||
2020 4 21 Motorola edge ("racer")
|
||||
2020 3 21 SHIFT SHIFT6mq ("axolotl")
|
||||
2020 3 21 Radxa Zero (Tablet) ("radxa0_tab", devkit)
|
||||
2020 3 21 Radxa Zero (Android TV) ("radxa0", devkit)
|
||||
2020 3 21 Motorola moto one 5G ace ("kiev")
|
||||
2020 3 21 Motorola moto g 5G ("kiev")
|
||||
2020 3 21 HardKernel ODROID-C4 (Tablet) ("odroidc4_tab", devkit)
|
||||
2020 2 21 Xiaomi Redmi Note 9S ("miatoll")
|
||||
2020 2 21 Xiaomi Redmi Note 9 Pro Max ("miatoll")
|
||||
2020 2 21 Xiaomi Redmi Note 9 Pro 5G ("gauguin")
|
||||
2020 2 21 Xiaomi Redmi Note 9 Pro (India) ("miatoll")
|
||||
2020 2 21 Xiaomi Redmi Note 9 Pro (Global) ("miatoll")
|
||||
2020 2 21 Xiaomi Redmi K30S Ultra ("apollon")
|
||||
2020 2 21 Xiaomi POCO X3 NFC ("surya")
|
||||
2020 2 21 Xiaomi POCO M2 Pro ("miatoll")
|
||||
2020 2 21 Xiaomi Mi 10T Pro ("apollon")
|
||||
2020 2 21 Xiaomi Mi 10T Lite 5G ("gauguin")
|
||||
2020 2 21 Xiaomi Mi 10T ("apollon")
|
||||
2020 2 21 Xiaomi Mi 10 ("umi")
|
||||
2020 2 21 Sony Xperia 5 II ("pdx206")
|
||||
2020 2 21 Samsung Galaxy Tab S6 Lite (Wi-Fi) ("gta4xlwifi", tablet)
|
||||
2020 2 21 Samsung Galaxy Tab S6 Lite (LTE) ("gta4xl", tablet)
|
||||
2020 2 21 OnePlus 8T ("kebab")
|
||||
2020 2 21 Motorola moto one 5G ("nairo")
|
||||
2020 2 21 Motorola moto g 5G plus ("nairo")
|
||||
2020 2 21 HardKernel ODROID-C4 (Android TV) ("odroidc4", devkit)
|
||||
2020 2 21 Google Chromecast with Google TV (4K) ("sabrina", set top box)
|
||||
2020 2 21 Banana Pi M5 (Tablet) ("m5_tab", devkit)
|
||||
2020 1 21 Xiaomi Redmi K30 Pro ("lmi")
|
||||
2020 1 21 Xiaomi POCO F2 Pro ("lmi")
|
||||
2020 1 21 Xiaomi Mi 10 Pro ("cmi")
|
||||
2020 1 21 Sony Xperia 1 II ("pdx203")
|
||||
2020 1 21 Samsung Galaxy Tab A7 10.4 2020 (Wi-Fi) ("gta4lwifi", tablet)
|
||||
2020 1 21 Samsung Galaxy Tab A7 10.4 2020 (LTE) ("gta4l", tablet)
|
||||
2020 1 21 Samsung Galaxy A71 ("a71")
|
||||
2020 1 21 OnePlus Nord N10 ("billie")
|
||||
2020 1 21 OnePlus 8 Pro ("instantnoodlep")
|
||||
2020 1 21 OnePlus 8 ("instantnoodle")
|
||||
2020 1 21 Motorola moto g9 power ("cebu")
|
||||
2020 1 21 Motorola moto g9 play ("guamp")
|
||||
2020 1 21 Motorola moto g9 ("guamp")
|
||||
2020 1 21 Motorola moto e7 plus ("guam")
|
||||
2020 1 21 Lenovo K12 Pro ("cebu")
|
||||
2020 1 21 Lenovo K12 Note ("guamp")
|
||||
2020 1 21 Google Pixel 5 ("redfin")
|
||||
2020 1 21 Google Pixel 4a 5G ("bramble")
|
||||
2020 1 21 Google Pixel 4a ("sunfish")
|
||||
2020 1 21 Banana Pi M5 (Android TV) ("m5", devkit)
|
||||
2019 6 21 F(x)tec Pro¹ ("pro1")
|
||||
2019 4 21 Motorola moto g7 play ("channel")
|
||||
2019 3 21 Nintendo Switch v2 [Tablet] ("nx_tab", handheld game console)
|
||||
2019 3 21 Nintendo Switch v2 [Android TV] ("nx", handheld game console)
|
||||
2019 3 21 Nintendo Switch Lite [Tablet] ("nx_tab", handheld game console)
|
||||
2019 3 21 Nintendo Switch Lite [Android TV] ("nx", handheld game console)
|
||||
2019 3 21 Motorola moto g7 power ("ocean")
|
||||
2019 3 21 Motorola moto g7 ("river")
|
||||
2019 3 21 Lenovo Z6 Pro ("zippo")
|
||||
2019 3 21 Google Pixel 4 XL ("coral")
|
||||
2019 3 21 Google Pixel 4 ("flame")
|
||||
2019 2 21 Samsung Galaxy Tab S5e (Wi-Fi) ("gts4lvwifi", tablet)
|
||||
2019 2 21 Samsung Galaxy Tab S5e (LTE) ("gts4lv", tablet)
|
||||
2019 2 21 Samsung Galaxy Note10 5G ("d1x")
|
||||
2019 2 21 OnePlus 7 Pro ("guacamole")
|
||||
2019 2 21 Nubia Mini 5G ("TP1803")
|
||||
2019 2 21 NVIDIA Shield TV (2019) [Android TV] ("sif", set top box)
|
||||
2019 2 21 NVIDIA Jetson Nano [Tablet] ("porg_tab", devkit)
|
||||
2019 2 21 NVIDIA Jetson Nano [Android TV] ("porg", devkit)
|
||||
2019 2 21 NVIDIA Jetson Nano 2GB [Tablet] ("porg_tab", devkit)
|
||||
2019 2 21 NVIDIA Jetson Nano 2GB [Android TV] ("porg", devkit)
|
||||
2019 2 21 Motorola p50 ("kane")
|
||||
2019 2 21 Motorola one vision ("kane")
|
||||
2019 2 21 Motorola one action ("troika")
|
||||
2019 2 21 Motorola moto g7 plus ("lake")
|
||||
2019 2 21 Lenovo Z5 Pro GT ("heart")
|
||||
2019 2 21 Google Pixel 3a XL ("bonito")
|
||||
2019 2 21 Google Pixel 3a ("sargo")
|
||||
2019 2 21 Fairphone 3+ ("FP3")
|
||||
2019 2 21 Fairphone 3 ("FP3")
|
||||
2019 1 21 Xiaomi Redmi Y3 ("onclite")
|
||||
2019 1 21 Xiaomi Redmi K20 (India) ("davinci")
|
||||
2019 1 21 Xiaomi Redmi K20 (China) ("davinci")
|
||||
2019 1 21 Xiaomi Redmi 8A Dual ("Mi439")
|
||||
2019 1 21 Xiaomi Redmi 8A ("Mi439")
|
||||
2019 1 21 Xiaomi Redmi 8 ("Mi439")
|
||||
2019 1 21 Xiaomi Redmi 7A ("Mi439")
|
||||
2019 1 21 Xiaomi Redmi 7 ("onclite")
|
||||
2019 1 21 Xiaomi Mi CC9 Meitu Edition ("vela")
|
||||
2019 1 21 Xiaomi Mi CC 9 ("pyxis")
|
||||
2019 1 21 Xiaomi Mi 9T ("davinci")
|
||||
2019 1 21 Xiaomi Mi 9 SE ("grus")
|
||||
2019 1 21 Xiaomi Mi 9 Lite ("pyxis")
|
||||
2019 1 21 Sony Xperia 10 Plus ("mermaid")
|
||||
2019 1 21 Sony Xperia 10 ("kirin")
|
||||
2019 1 21 Samsung Galaxy Tab A 8.0 (2019) ("gtowifi", tablet)
|
||||
2019 1 21 Samsung Galaxy S10e ("beyond0lte")
|
||||
2019 1 21 Samsung Galaxy S10+ ("beyond2lte")
|
||||
2019 1 21 Samsung Galaxy S10 5G ("beyondx")
|
||||
2019 1 21 Samsung Galaxy S10 ("beyond1lte")
|
||||
2019 1 21 Samsung Galaxy Note10+ 5G ("d2x")
|
||||
2019 1 21 Samsung Galaxy Note10+ ("d2s")
|
||||
2019 1 21 Samsung Galaxy Note10 ("d1")
|
||||
2019 1 21 OnePlus 7T Pro ("hotdog")
|
||||
2019 1 21 OnePlus 7T ("hotdogb")
|
||||
2019 1 21 OnePlus 7 ("guacamoleb")
|
||||
2018 3 21 Sony Xperia XA2 ("pioneer")
|
||||
2018 2 21 Xiaomi POCO F1 ("beryllium")
|
||||
2018 2 21 Xiaomi Mi MIX 3 ("perseus")
|
||||
2018 2 21 Xiaomi Black Shark ("shark")
|
||||
2018 2 21 Razer Phone 2 ("aura")
|
||||
2018 2 21 Nubia Z18 ("nx606j")
|
||||
2018 2 21 Nubia Red Magic Mars ("nx619j")
|
||||
2018 2 21 Google Pixel 3 XL ("crosshatch")
|
||||
2018 2 21 Google Pixel 3 ("blueline")
|
||||
2018 1 21 Xiaomi Mi MIX 2S ("polaris")
|
||||
2018 1 21 Xiaomi Mi 8 Pro ("equuleus")
|
||||
2018 1 21 Xiaomi Mi 8 Explorer Edition ("ursa")
|
||||
2018 1 21 Xiaomi Mi 8 ("dipper")
|
||||
2018 1 21 Sony Xperia XZ3 ("akatsuki")
|
||||
2018 1 21 Sony Xperia XZ2 Premium ("aurora")
|
||||
2018 1 21 Sony Xperia XZ2 Compact ("xz2c")
|
||||
2018 1 21 Sony Xperia XZ2 ("akari")
|
||||
2018 1 21 Sony Xperia XA2 Ultra ("discovery")
|
||||
2018 1 21 Sony Xperia XA2 Plus ("voyager")
|
||||
2018 1 21 OnePlus 6T ("fajita")
|
||||
2018 1 21 OnePlus 6 ("enchilada")
|
||||
2018 1 21 Nubia Z18 Mini ("nx611j")
|
||||
2018 1 21 Nokia 6.1 Plus ("DRG")
|
||||
2018 1 21 Nokia 6.1 (2018) ("PL2")
|
||||
2018 1 21 Motorola moto z3 play ("beckham")
|
||||
2018 1 21 Motorola moto z3 ("messi")
|
||||
2018 1 21 Motorola moto g6 plus ("evert")
|
||||
2018 1 21 LG V40 ThinQ ("judypn")
|
||||
2018 1 21 LG V35 ThinQ ("judyp")
|
||||
2018 1 21 LG G7+ ThinQ ("judyln")
|
||||
2018 1 21 LG G7 ThinQ (G710ULM/VMX) ("g710ulm")
|
||||
2018 1 21 LG G7 ThinQ (G710N) ("g710n")
|
||||
2018 1 21 LG G7 ThinQ (G710AWM/EM/EMW) ("judyln")
|
||||
2018 1 21 ASUS Zenfone 5Z (ZS620KL) ("Z01R")
|
||||
2017 4 21 Google Pixel 2 XL ("taimen")
|
||||
2017 4 21 Google Pixel 2 ("walleye")
|
||||
2017 3 21 Nintendo Switch v1 [Tablet] ("nx_tab", handheld game console)
|
||||
2017 3 21 Nintendo Switch v1 [Android TV] ("nx", handheld game console)
|
||||
2017 3 21 Motorola moto z2 force ("nash")
|
||||
2017 3 21 Motorola moto z (2018) ("nash")
|
||||
2017 3 21 Motorola moto x4 ("payton")
|
||||
2017 3 21 Essential PH-1 ("mata")
|
||||
2017 2 21 Xiaomi Mi 6 ("sagit")
|
||||
2017 2 21 Razer Phone ("cheryl")
|
||||
2017 2 21 LG V30 (Unlocked) ("joan")
|
||||
2017 2 21 LG V30 (T-Mobile) ("joan")
|
||||
2017 2 21 LG V30 (Other) ("joan")
|
||||
2017 1 21 Xiaomi Redmi Y1 Prime ("Mi8937")
|
||||
2017 1 21 Xiaomi Redmi Y1 Lite ("Mi8917")
|
||||
2017 1 21 Xiaomi Redmi Note 5A Prime ("Mi8937")
|
||||
2017 1 21 Xiaomi Redmi Note 5A Lite ("Mi8917")
|
||||
2017 1 21 Xiaomi Redmi 5A ("Mi8917")
|
||||
2017 1 21 Xiaomi Redmi 4X ("Mi8937")
|
||||
2017 1 21 Xiaomi Redmi 4 (India) ("Mi8937")
|
||||
2017 1 21 Xiaomi Mi MIX 2 ("chiron")
|
||||
2017 1 21 OnePlus 5T ("dumpling")
|
||||
2017 1 21 OnePlus 5 ("cheeseburger")
|
||||
2017 1 21 Nokia 8 ("NB1")
|
||||
2017 1 21 NVIDIA Jetson TX2 [Tablet] ("quill_tab", devkit)
|
||||
2017 1 21 NVIDIA Jetson TX2 [Android TV] ("quill", devkit)
|
||||
2017 1 21 NVIDIA Jetson TX2 NX [Tablet] ("quill_tab", devkit)
|
||||
2017 1 21 NVIDIA Jetson TX2 NX [Android TV] ("quill", devkit)
|
||||
2016 2 21 Xiaomi Mi 5 ("gemini")
|
||||
2016 2 21 Google Pixel XL ("marlin")
|
||||
2016 2 21 Google Pixel ("sailfish")
|
||||
2016 1 21 Xiaomi Redmi 4A ("Mi8917")
|
||||
2016 1 21 Xiaomi Redmi 3X ("Mi8937")
|
||||
2016 1 21 Xiaomi Redmi 3S ("Mi8937")
|
||||
2016 1 21 Xiaomi Mi 5s Plus ("natrium")
|
||||
2015 2 21 NVIDIA Shield TV (2015 / 2015 Pro / 2017 / 2019 Pro) [Tablet] ("foster_tab", set top box)
|
||||
2015 2 21 NVIDIA Shield TV (2015 / 2015 Pro / 2017 / 2019 Pro) [Android TV] ("foster", set top box)
|
||||
2015 2 21 NVIDIA Jetson TX1 [Tablet] ("foster_tab", set top box)
|
||||
2015 2 21 NVIDIA Jetson TX1 [Android TV] ("foster", set top box)
|
||||
2021 3 20 ASUS ZenFone 8 ("sake")
|
||||
2021 1 20 Xiaomi POCO X3 Pro ("vayu")
|
||||
2020 2 20 Xiaomi Redmi Note 9 ("merlinx")
|
||||
2020 1 20 Xiaomi Redmi 9 ("lancelot")
|
||||
2020 1 20 Nubia Red Magic 5S (Global) ("nx659j")
|
||||
2020 1 20 Nubia Red Magic 5S (China) ("nx659j")
|
||||
2020 1 20 Nubia Red Magic 5G (Global) ("nx659j")
|
||||
2020 1 20 Nubia Red Magic 5G (China) ("nx659j")
|
||||
2020 1 20 Motorola one fusion+ (India) ("liber")
|
||||
2020 1 20 Motorola one fusion+ ("liber")
|
||||
2019 2 20 Xiaomi Redmi Note 7 Pro ("violet")
|
||||
2019 1 20 LG V50S ThinQ ("mh2lm")
|
||||
2019 1 20 LG G8s ThinQ ("betalm")
|
||||
2019 1 20 LG G8X ThinQ (G850QM/UM) ("mh2lm")
|
||||
2019 1 20 LG G8X ThinQ (G850EM/EMW) ("mh2lm")
|
||||
2019 1 20 LG G8 ThinQ (Korea) ("alphaplus")
|
||||
2018 1 20 Xiaomi Mi 8 SE ("xmsirius")
|
||||
2018 1 20 Samsung Galaxy S9+ ("star2lte")
|
||||
2018 1 20 Samsung Galaxy S9 ("starlte")
|
||||
2018 1 20 Samsung Galaxy Note 9 ("crownlte")
|
||||
2018 1 20 BQ Aquaris X2 Pro ("zangyapro")
|
||||
2018 1 20 BQ Aquaris X2 ("zangya")
|
||||
2018 1 20 ASUS Zenfone Max Pro M1 ("X00TD")
|
||||
2017 2 20 BQ Aquaris X Pro ("bardockpro")
|
||||
2017 2 20 BQ Aquaris X ("bardock")
|
||||
2017 1 20 Xiaomi Mi A1 ("tissot")
|
||||
2017 1 20 10.or G ("G")
|
||||
2016 1 20 ZUK Z2 Plus ("z2_plus")
|
||||
2022 0 21 Xiaomi POCO M5s ("rosemary")
|
||||
2021 0 21 Xiaomi Redmi Note 10S NFC ("rosemary")
|
||||
2021 0 21 Xiaomi Redmi Note 10S Latin America ("rosemary")
|
||||
2021 0 21 Xiaomi Redmi Note 10S ("rosemary")
|
||||
2021 0 21 Samsung Galaxy S20 FE ("r8q")
|
||||
2020 0 21 Samsung Galaxy S20 FE 5G ("r8q")
|
||||
2020 0 21 OnePlus Nord ("avicii")
|
||||
2020 0 21 Nubia Red Magic 5G Lite ("nx651j")
|
||||
2020 0 21 Nubia Play 5G ("nx651j")
|
||||
2018 0 21 Nubia Red Magic ("nx609j")
|
||||
2017 0 21 Nubia Z17 ("nx563j")
|
||||
2017 0 21 LG G6 (US Unlocked) ("us997")
|
||||
2017 0 21 LG G6 (T-Mobile) ("h872")
|
||||
2017 0 21 LG G6 (EU Unlocked) ("h870")
|
||||
2016 0 21 LG V20 (Verizon) ("vs995")
|
||||
2016 0 21 LG V20 (T-Mobile) ("h918")
|
||||
2016 0 21 LG V20 (Sprint) ("ls997")
|
||||
2016 0 21 LG V20 (Global) ("h990")
|
||||
2016 0 21 LG V20 (GSM Unlocked) ("us996")
|
||||
2016 0 21 LG V20 (GSM Unlocked - DirtySanta) ("us996d")
|
||||
2016 0 21 LG V20 (AT&T) ("h910")
|
||||
2016 0 21 LG G5 (US Unlocked) ("rs988")
|
||||
2016 0 21 LG G5 (T-Mobile) ("h830")
|
||||
2016 0 21 LG G5 (International) ("h850")
|
||||
2022 0 20 Nothing Phone (1) ("Spacewar")
|
||||
2020 0 20 Xiaomi Redmi K30 Pro Zoom Edition ("lmi")
|
||||
2019 0 20 Motorola one zoom ("parker")
|
||||
2017 0 20 LG V30 (T-Mobile) ("h932")
|
||||
2020 0 19.1 Xiaomi Mi 10 Lite 5G ("monet")
|
||||
2018 0 19.1 Motorola one power ("chef")
|
||||
2020 0 18.1 ASUS ROG Phone 3 ("obiwan")
|
||||
2019 0 18.1 Xiaomi Redmi Note 8T ("ginkgo")
|
||||
2019 0 18.1 Xiaomi Redmi Note 8 ("ginkgo")
|
||||
2019 0 18.1 Xiaomi Redmi Note 7 ("lavender")
|
||||
2019 0 18.1 Samsung Galaxy M20 ("m20lte")
|
||||
2018 0 18.1 Xiaomi Redmi Note 6 Pro ("twolip")
|
||||
2018 0 18.1 Xiaomi Redmi Note 5 Pro ("whyred")
|
||||
2018 0 18.1 Xiaomi Mi A2 ("jasmine_sprout")
|
||||
2018 0 18.1 Xiaomi Mi 8 Lite ("platina")
|
||||
2018 0 18.1 Xiaomi Mi 6X ("wayne")
|
||||
2018 0 18.1 Motorola moto e5 plus (XT1924-6/7/8) ("hannah")
|
||||
2018 0 18.1 Motorola moto e5 plus (XT1924-3/9) ("ahannah")
|
||||
2018 0 18.1 Motorola moto e5 plus (XT1924-1/2/4/5) ("rhannah")
|
||||
2018 0 18.1 ASUS Zenfone Max Pro M2 ("X01BD")
|
||||
2018 0 18.1 ASUS Zenfone Max M2 ("X01AD")
|
||||
2018 0 18.1 ASUS Zenfone Max M1 ("X00P")
|
||||
2017 0 18.1 Xiaomi Mi Note 3 ("jason")
|
||||
2017 0 18.1 Samsung Galaxy A7 (2017) ("a7y17lte")
|
||||
2017 0 18.1 Samsung Galaxy A5 (2017) ("a5y17lte")
|
||||
2017 0 18.1 Motorola moto z2 play ("albus")
|
||||
2017 0 18.1 Motorola moto g5s ("montana")
|
||||
2017 0 18.1 Motorola moto g5 ("cedric")
|
||||
2017 0 18.1 LeEco Le Pro3 Elite ("zl1")
|
||||
2016 0 18.1 Xiaomi Mi Note 2 ("scorpio")
|
||||
2016 0 18.1 Xiaomi Mi MIX ("lithium")
|
||||
2016 0 18.1 Sony Xperia X Compact ("kugo")
|
||||
2016 0 18.1 Sony Xperia X ("suzu")
|
||||
2016 0 18.1 OnePlus 3T ("oneplus3")
|
||||
2016 0 18.1 OnePlus 3 ("oneplus3")
|
||||
2016 0 18.1 Nextbit Robin ("ether")
|
||||
2016 0 18.1 Motorola moto z play ("addison")
|
||||
2016 0 18.1 Motorola moto z ("griffin")
|
||||
2016 0 18.1 Lenovo Yoga Tab 3 Plus Wi-Fi ("YTX703F", tablet)
|
||||
2016 0 18.1 Lenovo Yoga Tab 3 Plus LTE ("YTX703L", tablet)
|
||||
2016 0 18.1 Lenovo P2 ("kuntao")
|
||||
2016 0 18.1 LeEco Le Pro3 ("zl1")
|
||||
2016 0 18.1 LeEco Le Max2 ("x2")
|
||||
2015 0 18.1 Fairphone 2 ("FP2")
|
||||
2014 0 18.1 Sony Xperia Z3 Compact ("z3c")
|
||||
2014 0 18.1 Sony Xperia Z3 ("z3")
|
||||
2014 0 18.1 Sony Xperia Z2 ("sirius")
|
||||
2014 0 18.1 Sony Xperia Tablet Z2 Wi-Fi ("castor_windy", tablet)
|
||||
2014 0 18.1 Sony Xperia Tablet Z2 LTE ("castor", tablet)
|
||||
2014 0 18.1 Samsung SM-G900MD ("klteduos")
|
||||
2014 0 18.1 Samsung SM-G900FD ("klteduos")
|
||||
2014 0 18.1 Samsung SM-G9009W ("kltechnduo")
|
||||
2014 0 18.1 Samsung SM-G9008W ("kltechnduo")
|
||||
2014 0 18.1 Samsung SM-G9008V ("kltechn")
|
||||
2014 0 18.1 Samsung SM-G9006W ("kltechnduo")
|
||||
2014 0 18.1 Samsung SM-G9006V ("kltechn")
|
||||
2014 0 18.1 Samsung Galaxy S5 LTE (SC-04F/SCL23) ("kltekdi")
|
||||
2014 0 18.1 Samsung Galaxy S5 LTE (G900K/L/S) ("kltekor")
|
||||
2014 0 18.1 Samsung Galaxy S5 LTE (G900I/P) ("kltedv")
|
||||
2014 0 18.1 Samsung Galaxy S5 LTE (G900F/M/R4/R7/T/T3/V/W8) ("klte")
|
||||
2014 0 18.1 Samsung Galaxy S5 LTE (G900AZ/S902L) ("klteaio")
|
||||
2014 0 18.1 Samsung Galaxy S5 Active (G870F) ("klteactivexx")
|
||||
2014 0 18.1 Samsung Galaxy S4 Value Edition (GT-I9515/L) ("jfvelte")
|
||||
2014 0 18.1 Samsung Galaxy S III Neo (Sony Camera) ("s3ve3gxx")
|
||||
2014 0 18.1 Samsung Galaxy S III Neo (Samsung Camera) ("s3ve3gjv")
|
||||
2014 0 18.1 Samsung Galaxy S III Neo (Dual SIM) ("s3ve3gds")
|
||||
2014 0 18.1 OnePlus One ("bacon")
|
||||
2014 0 18.1 Motorola moto x (2014) ("victara")
|
||||
2014 0 18.1 LG G3 (Verizon) ("vs985")
|
||||
2014 0 18.1 LG G3 (T-Mobile) ("d851")
|
||||
2014 0 18.1 LG G3 (Sprint) ("ls990")
|
||||
2014 0 18.1 LG G3 (Korea) ("f400")
|
||||
2014 0 18.1 LG G3 (International) ("d855")
|
||||
2014 0 18.1 LG G3 (Canada) ("d852")
|
||||
2014 0 18.1 LG G3 (AT&T) ("d850")
|
||||
2014 0 18.1 Google Nexus 6 ("shamu")
|
||||
2013 0 18.1 Samsung Galaxy S4 Active ("jactivelte")
|
||||
2013 0 18.1 Samsung Galaxy S4 (SGH-I337) ("jflteatt")
|
||||
2013 0 18.1 Samsung Galaxy S4 (SCH-R970, SPH-L720) ("jfltespr")
|
||||
2013 0 18.1 Samsung Galaxy S4 (SCH-I545) ("jfltevzw")
|
||||
2013 0 18.1 Samsung Galaxy S4 (GT-I9505, SGH-I337M, SGH-M919/V) ("jfltexx")
|
||||
2013 0 18.1 Samsung Galaxy Note 3 LTE (N900T/V/W8) ("hltetmo")
|
||||
2013 0 18.1 Samsung Galaxy Note 3 LTE (N900K/L/S) ("hltekor")
|
||||
2013 0 18.1 Samsung Galaxy Note 3 LTE (N9008V) ("hltechn")
|
||||
2013 0 18.1 Samsung Galaxy Note 3 LTE (N9005/P) ("hlte")
|
||||
2013 0 18.1 LG G2 (T-Mobile) ("d801")
|
||||
2013 0 18.1 LG G2 (International) ("d802")
|
||||
2013 0 18.1 LG G2 (Canadian) ("d803")
|
||||
2013 0 18.1 LG G2 (AT&T) ("d800")
|
||||
2013 0 18.1 Google Nexus 7 2013 (Wi-Fi, Repartitioned) ("flox", tablet)
|
||||
2013 0 18.1 Google Nexus 7 2013 (LTE, Repartitioned) ("debx", tablet)
|
||||
2019 0 17.1 NVIDIA Shield TV 2019 Pro [Tablet] ("mdarcy_tab", set top box)
|
||||
2019 0 17.1 NVIDIA Shield TV 2019 Pro [Android TV] ("mdarcy", set top box)
|
||||
2019 0 17.1 ASUS Zenfone 6 (ZS630KL) ("I01WD")
|
||||
2019 0 17.1 ASUS ROG Phone 2 (ZS660KL) ("I001D")
|
||||
2018 0 17.1 Yandex Phone ("Amber")
|
||||
2018 0 17.1 Realme 2 Pro ("RMX1801")
|
||||
2016 0 17.1 Motorola moto g4 play ("harpia")
|
||||
2016 0 17.1 LeEco Le 2 ("s2")
|
||||
2015 0 17.1 Wingtech Redmi 2 ("wt88047")
|
||||
2015 0 17.1 Wileyfox Swift ("crackling")
|
||||
2015 0 17.1 Samsung Galaxy S5 Neo ("s5neolte")
|
||||
2015 0 17.1 Samsung Galaxy J7 (2015) ("j7elte")
|
||||
2015 0 17.1 Samsung Galaxy A7 (2016) ("a7xelte")
|
||||
2015 0 17.1 Samsung Galaxy A5 (2016) ("a5xelte")
|
||||
2015 0 17.1 Samsung Galaxy A3 (2016) ("a3xelte")
|
||||
2015 0 17.1 OnePlus 2 ("oneplus2")
|
||||
2015 0 17.1 Motorola moto x play ("lux")
|
||||
2015 0 17.1 Motorola moto g3 turbo ("merlin")
|
||||
2015 0 17.1 Motorola moto g (2015) ("osprey")
|
||||
2015 0 17.1 Motorola moto e LTE (2015) ("surnia")
|
||||
2015 0 17.1 Huawei Honor 5X ("kiwi")
|
||||
2014 0 17.1 HTC One (M8) Dual SIM ("m8d")
|
||||
2014 0 17.1 HTC One (M8) ("m8")
|
||||
2019 0 16.0 Realme 3 Pro ("RMX1851")
|
||||
2018 0 16.0 Huawei P20 Pro ("charlotte")
|
||||
2018 0 16.0 Huawei P20 Lite ("anne")
|
||||
2018 0 16.0 Huawei Honor View 10 ("berkeley")
|
||||
2017 0 16.0 Xiaomi Redmi Note 4 ("mido")
|
||||
2017 0 16.0 Xiaomi Redmi 4(X) ("santoni")
|
||||
2017 0 16.0 Huawei P Smart ("figo")
|
||||
2016 0 16.0 Xiaomi Redmi 3S / 3X ("land")
|
||||
2016 0 16.0 Xiaomi Mi 5s ("capricorn")
|
||||
2016 0 16.0 Samsung Galaxy Tab S2 9.7 Wi-Fi (2016) ("gts210vewifi", tablet)
|
||||
2016 0 16.0 Samsung Galaxy Tab S2 8.0 Wi-Fi (2016) ("gts28vewifi", tablet)
|
||||
2016 0 16.0 OPPO F1 (International) ("f1f")
|
||||
2016 0 16.0 ASUS Zenfone 3 ("zenfone3")
|
||||
2015 0 16.0 ZUK Z1 ("ham")
|
||||
2015 0 16.0 YU Yuphoria ("lettuce")
|
||||
2015 0 16.0 Wileyfox Storm ("kipper")
|
||||
2015 0 16.0 OPPO R7s (International) ("r7sf")
|
||||
2015 0 16.0 OPPO R7 Plus (International) ("r7plus")
|
||||
2015 0 16.0 OPPO R5s (International) ("r5")
|
||||
2014 0 16.0 Samsung Galaxy S5 Plus ("kccat6")
|
||||
2014 0 16.0 Samsung Galaxy S5 LTE-A ("lentislte")
|
||||
2014 0 16.0 OPPO R5 (International) ("r5")
|
||||
2014 0 16.0 OPPO Find 7s ("find7")
|
||||
2014 0 16.0 OPPO Find 7a ("find7")
|
||||
2013 0 16.0 Samsung Galaxy Grand 2 Duos ("ms013g")
|
||||
2016 0 15.1 ZTE Axon 7 ("axon7")
|
||||
2015 0 15.1 HTC One A9 ("hiae")
|
||||
2015 0 15.1 Google Pixel C ("dragon", tablet)
|
||||
2015 0 15.1 Google Nexus 6P ("angler")
|
||||
2015 0 15.1 Google Nexus 5X ("bullhead")
|
||||
2015 0 15.1 ASUS Zenfone 2 Selfie (1080p) ("Z00T")
|
||||
2015 0 15.1 ASUS Zenfone 2 Laser (720p) ("Z00L")
|
||||
2015 0 15.1 ASUS Zenfone 2 Laser (1080p) ("Z00T")
|
||||
2014 0 15.1 NVIDIA Shield Tablet ("shieldtablet", tablet)
|
||||
2014 0 15.1 Huawei Honor 4x (China Telecom) ("che10")
|
||||
2014 0 15.1 Huawei Honor 4X ("cherry")
|
||||
2014 0 15.1 Huawei Honor 4 ("cherry")
|
||||
2014 0 15.1 Google Nexus Player ("fugu", set top box)
|
||||
2013 0 15.1 Sony Xperia ZR ("dogo")
|
||||
2013 0 15.1 Sony Xperia ZL ("odin")
|
||||
2013 0 15.1 Sony Xperia Z ("yuga")
|
||||
2013 0 15.1 Sony Xperia Tablet Z Wi-Fi ("pollux_windy", tablet)
|
||||
2013 0 15.1 Sony Xperia Tablet Z LTE ("pollux", tablet)
|
||||
2013 0 15.1 Sony Xperia SP ("huashan")
|
||||
2012 0 15.1 Sony Xperia V ("tsubasa")
|
||||
2012 0 15.1 Sony Xperia TX ("hayabusa")
|
||||
2012 0 15.1 Sony Xperia T ("mint")
|
||||
2012 0 15.1 Google Nexus 4 ("mako")
|
||||
2016 0 14.1 ZTE Axon 7 Mini ("tulip")
|
||||
2016 0 14.1 ZTE AT&T Trek 2 HD ("jasmine", tablet)
|
||||
2016 0 14.1 Xiaomi Redmi Note 3 ("kenzo")
|
||||
2016 0 14.1 Xiaomi Redmi 3 Prime ("ido")
|
||||
2016 0 14.1 Xiaomi Redmi 3 ("ido")
|
||||
2016 0 14.1 Xiaomi Mi Max ("hydrogen")
|
||||
2016 0 14.1 Samsung Galaxy Tab E 8.0 LTE (Sprint) ("gtesqltespr", tablet)
|
||||
2016 0 14.1 Samsung Galaxy Tab 3 7.0 LTE ("lt02ltespr", tablet)
|
||||
2016 0 14.1 Samsung Galaxy S7 Edge ("hero2lte")
|
||||
2016 0 14.1 Samsung Galaxy S7 ("herolte")
|
||||
2016 0 14.1 Motorola moto g4 ("athene")
|
||||
2016 0 14.1 Lenovo Vibe K5 Plus ("A6020")
|
||||
2016 0 14.1 Lenovo Vibe K5 ("A6020")
|
||||
2016 0 14.1 LG K10 ("m216")
|
||||
2016 0 14.1 LG G Pad X (T-Mobile) ("v521", tablet)
|
||||
2016 0 14.1 HTC 10 ("pme")
|
||||
2016 0 14.1 BQ Aquaris X5 Plus ("gohan")
|
||||
2016 0 14.1 BQ Aquaris U Plus ("tenshi")
|
||||
2016 0 14.1 BQ Aquaris U ("chaozu")
|
||||
2015 0 14.1 YU Yureka Plus ("tomato")
|
||||
2015 0 14.1 YU Yunique ("jalebi")
|
||||
2015 0 14.1 Xiaomi Mi 4c ("libra")
|
||||
2015 0 14.1 Sony Xperia Z5 Compact ("suzuran")
|
||||
2015 0 14.1 Sony Xperia Z5 ("sumire")
|
||||
2015 0 14.1 Sony Xperia Z4 Tablet WiFi ("karin_windy", tablet)
|
||||
2015 0 14.1 Sony Xperia Z4 Tablet LTE ("karin", tablet)
|
||||
2015 0 14.1 Sony Xperia Z3+ ("ivy")
|
||||
2015 0 14.1 Samsung Galaxy Tab S2 9.7 (Wi-Fi) ("gts210wifi", tablet)
|
||||
2015 0 14.1 Samsung Galaxy Tab S2 9.7 (LTE) ("gts210ltexx", tablet)
|
||||
2015 0 14.1 Samsung Galaxy Tab E 9.6 (WiFi) ("gtelwifiue", tablet)
|
||||
2015 0 14.1 Samsung Galaxy S6 Edge ("zeroltexx")
|
||||
2015 0 14.1 Samsung Galaxy S6 ("zerofltexx")
|
||||
2015 0 14.1 OnePlus X ("onyx")
|
||||
2015 0 14.1 OPPO N3 ("n3")
|
||||
2015 0 14.1 Nubia Z9 Max ("nx512j")
|
||||
2015 0 14.1 Motorola moto x style (2015) ("clark")
|
||||
2015 0 14.1 Motorola moto x pure edition (2015) ("clark")
|
||||
2015 0 14.1 Motorola moto g LTE (2014) ("thea")
|
||||
2015 0 14.1 Motorola moto e (2015) ("otus")
|
||||
2015 0 14.1 LG G4 (T-Mobile) ("h811")
|
||||
2015 0 14.1 LG G4 (International) ("h815")
|
||||
2015 0 14.1 HTC One M9 (Verizon) ("himawl")
|
||||
2015 0 14.1 HTC One M9 (GSM) ("himaul")
|
||||
2015 0 14.1 Google Android One 2nd Gen ("seed")
|
||||
2015 0 14.1 BQ Aquaris X5 ("paella")
|
||||
2015 0 14.1 BQ Aquaris M5 ("piccolo")
|
||||
2015 0 14.1 BQ Aquaris E5s ("vegetalte")
|
||||
2015 0 14.1 ASUS Zenfone 2 (ZE500CL) ("Z00D")
|
||||
2015 0 14.1 ASUS Zenfone 2 (720p) ("Z008")
|
||||
2015 0 14.1 ASUS Zenfone 2 (1080p) ("Z00A")
|
||||
2015 0 14.1 ASUS ZenPad 8.0 (Z380KL) ("P024", tablet)
|
||||
2015 0 14.1 ARK Benefit A3 ("peach")
|
||||
2014 0 14.1 YU Yureka ("tomato")
|
||||
2014 0 14.1 Xiaomi Redmi 1S ("armani")
|
||||
2014 0 14.1 Xiaomi Mi 4 ("cancro")
|
||||
2014 0 14.1 Samsung Galaxy Tab S 8.4 Wi-Fi ("klimtwifi", tablet)
|
||||
2014 0 14.1 Samsung Galaxy Tab S 10.5 Wi-Fi ("chagallwifi", tablet)
|
||||
2014 0 14.1 Samsung Galaxy Tab S 10.5 LTE ("chagalllte", tablet)
|
||||
2014 0 14.1 Samsung Galaxy Tab PRO 10.1 ("n2awifi", tablet)
|
||||
2014 0 14.1 Samsung Galaxy S5 Sport ("kltesprsports")
|
||||
2014 0 14.1 Samsung Galaxy S5 (International 3G) ("k3gxx")
|
||||
2014 0 14.1 Samsung Galaxy Note Pro 12.2 Wi-Fi ("v1awifi", tablet)
|
||||
2014 0 14.1 Motorola moto g 4G ("peregrine")
|
||||
2014 0 14.1 Motorola moto g (2014) ("titan")
|
||||
2014 0 14.1 Motorola moto e ("condor")
|
||||
2014 0 14.1 Lenovo Vibe Z2 Pro ("kingdom")
|
||||
2014 0 14.1 LG Optimus L70 ("w5")
|
||||
2014 0 14.1 LG L90 ("w7")
|
||||
2014 0 14.1 LG G3 S ("jag3gds")
|
||||
2014 0 14.1 LG G3 Beat ("jagnm")
|
||||
2014 0 14.1 LG G2 Mini ("g2m")
|
||||
2014 0 14.1 LG G Pad 8.0 (Wi-Fi) ("v480", tablet)
|
||||
2014 0 14.1 LG G Pad 7.0 WiFi ("v400", tablet)
|
||||
2014 0 14.1 LG G Pad 7.0 (LTE) ("v410", tablet)
|
||||
2014 0 14.1 Huawei Ascend Mate 2 4G ("mt2")
|
||||
2014 0 14.1 Google Nexus 9 (Wi-Fi) ("flounder", tablet)
|
||||
2014 0 14.1 Google Nexus 9 (LTE) ("flounder_lte", tablet)
|
||||
2014 0 14.1 BQ Aquaris E5 4G ("vegetalte")
|
||||
2013 0 14.1 Xiaomi Mi 3 ("cancro")
|
||||
2013 0 14.1 Sony Xperia M ("nicki")
|
||||
2013 0 14.1 Sony Xperia L ("taoshan")
|
||||
2013 0 14.1 Samsung Galaxy S4 Mini (International LTE) ("serranoltexx")
|
||||
2013 0 14.1 Samsung Galaxy S4 Mini (International Dual SIM) ("serranodsdd")
|
||||
2013 0 14.1 Samsung Galaxy S4 Mini (International 3G) ("serrano3gxx")
|
||||
2013 0 14.1 Samsung Galaxy Note 8.0 (Wi-Fi) ("n5110", tablet)
|
||||
2013 0 14.1 Samsung Galaxy Note 8.0 (LTE) ("n5120", tablet)
|
||||
2013 0 14.1 Samsung Galaxy Note 8.0 (GSM) ("n5100", tablet)
|
||||
2013 0 14.1 Samsung Galaxy Note 3 (International 3G) ("ha3g")
|
||||
2013 0 14.1 Samsung Galaxy Note 10.1 Wi-Fi (2014) ("n1awifi", tablet)
|
||||
2013 0 14.1 Samsung Galaxy Note 10.1 2014 (LTE) ("lt03lte", tablet)
|
||||
2013 0 14.1 Motorola moto g ("falcon")
|
||||
2013 0 14.1 LG G Pad 8.3 ("v500", tablet)
|
||||
2013 0 14.1 HTC One Max (Verizon) ("t6vzw")
|
||||
2013 0 14.1 HTC One Max (GSM) ("t6")
|
||||
2013 0 14.1 HTC One (Verizon) ("m7vzw")
|
||||
2013 0 14.1 HTC One (GSM) ("m7")
|
||||
2013 0 14.1 Google Nexus 7 2013 (LTE) ("deb", tablet)
|
||||
2013 0 14.1 Google Nexus 7 (Wi-Fi, 2013 version) ("flo", tablet)
|
||||
2013 0 14.1 Google Nexus 5 ("hammerhead")
|
||||
2012 0 14.1 Samsung Galaxy S III (Verizon) ("d2vzw")
|
||||
2012 0 14.1 Samsung Galaxy S III (T-Mobile) ("d2tmo")
|
||||
2012 0 14.1 Samsung Galaxy S III (Sprint) ("d2spr")
|
||||
2012 0 14.1 Samsung Galaxy S III (LTE / International) ("i9305")
|
||||
2012 0 14.1 Samsung Galaxy S III (International) ("i9300")
|
||||
2012 0 14.1 Samsung Galaxy S III (AT&T) ("d2att")
|
||||
2012 0 14.1 Samsung Galaxy Note 2 (LTE) ("t0lte")
|
||||
2012 0 14.1 Motorola PHOTON Q 4G LTE ("xt897")
|
||||
2012 0 14.1 Motorola DROID 4 ("maserati")
|
||||
2011 0 14.1 Samsung Galaxy S II ("i9100")
|
||||
2011 0 14.1 Motorola DROID RAZR MAXX (GSM) ("umts_spyder")
|
||||
2011 0 14.1 Motorola DROID RAZR MAXX (CDMA) ("spyder")
|
||||
2011 0 14.1 Motorola DROID RAZR (GSM) ("umts_spyder")
|
||||
2011 0 14.1 Motorola DROID RAZR (CDMA) ("spyder")
|
||||
2011 0 14.1 Motorola DROID BIONIC ("targa")
|
||||
2014 0 13.0 Samsung Galaxy Tab Pro 8.4 ("mondrianwifi", tablet)
|
||||
2013 0 13.0 Samsung Galaxy S4 LTE-A (GT-I9506) ("ks01lte")
|
||||
2013 0 13.0 NVIDIA Shield Portable ("roth", handheld game console)
|
||||
2013 0 13.0 Motorola moto x ("ghost")
|
||||
2012 0 13.0 Samsung Galaxy Tab 2 7.0 (Wi-Fi / Wi-Fi + IR) ("espressowifi", tablet)
|
||||
2012 0 13.0 Samsung Galaxy Tab 2 7.0 (GSM) ("espresso3g", tablet)
|
||||
2012 0 13.0 Samsung Galaxy Tab 2 10.1 (Wi-Fi / Wi-Fi + IR) ("espressowifi", tablet)
|
||||
2012 0 13.0 Samsung Galaxy Tab 2 10.1 (GSM) ("espresso3g", tablet)
|
||||
2012 0 13.0 Google Nexus 10 ("manta", tablet)
|
||||
2012 0 13.0 Google Galaxy Nexus LTE (Sprint) ("toroplus")
|
||||
2011 0 13.0 Google Galaxy Nexus LTE (Verizon) ("toro")
|
||||
2011 0 13.0 Google Galaxy Nexus GSM ("maguro")
|
||||
#### Last Update: Sun Dec 22 19:48:22 2024 +0100 ####
|
||||
BIN
_resources/linux 1.pdf
Normal file
BIN
_resources/linux.pdf
Normal file
525
_resources/main-1.go
Normal file
|
|
@ -0,0 +1,525 @@
|
|||
//go:build linux
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
)
|
||||
|
||||
var w *tabwriter.Writer
|
||||
|
||||
type Process struct {
|
||||
PID int
|
||||
Command string
|
||||
CPUTime uint64 // clock ticks
|
||||
RSSPages uint64
|
||||
SwapBytes uint64
|
||||
}
|
||||
|
||||
type Snapshot struct {
|
||||
Processes map[int]Process
|
||||
TotalCPU uint64
|
||||
}
|
||||
|
||||
const INPUT_FILENAME = "/home/hpmi/Videos/imp/tests/others/go/process_info/input/process.txt"
|
||||
|
||||
func getProcessList() (processes []string, err error) {
|
||||
file, err := os.Open(INPUT_FILENAME)
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("err: ", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sc := bufio.NewScanner(file)
|
||||
|
||||
processes = []string{}
|
||||
|
||||
for sc.Scan() {
|
||||
processes = append(processes, sc.Text())
|
||||
}
|
||||
|
||||
if err := sc.Err(); err != nil {
|
||||
log.Fatalf("Error reading file: %s", err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func printResultOfKeyword(keyword string) {
|
||||
keyword = strings.ToLower(keyword)
|
||||
|
||||
interval := time.Second / 10
|
||||
|
||||
numCPU := uint64(os.Getuid()) // replaced below
|
||||
_ = numCPU
|
||||
|
||||
cpuCount := uint64(getCPUCount())
|
||||
|
||||
if cpuCount == 0 {
|
||||
cpuCount = 1
|
||||
}
|
||||
|
||||
// First snapshot.
|
||||
first, err := takeSnapshot(keyword)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "snapshot error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// _ = interval
|
||||
time.Sleep(interval)
|
||||
|
||||
// Second snapshot.
|
||||
second, err := takeSnapshot(keyword)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "snapshot error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
result := calculate(first, second, cpuCount)
|
||||
|
||||
printResult(keyword, result)
|
||||
}
|
||||
|
||||
func main() {
|
||||
w = tabwriter.NewWriter(os.Stdout, 1, 1, 3, ' ', 0)
|
||||
|
||||
defer w.Flush()
|
||||
|
||||
if len(os.Args) < 2 {
|
||||
// fmt.Printf("Usage: %s <keyword> [interval]\n", os.Args[0])
|
||||
// fmt.Printf("\nExamples:\n")
|
||||
// fmt.Printf(" %s firefox\n", os.Args[0])
|
||||
// fmt.Printf(" %s firefox 1\n", os.Args[0])
|
||||
// os.Exit(1)
|
||||
|
||||
processes, err := getProcessList()
|
||||
|
||||
if err != nil {
|
||||
fmt.Println("err: ", err)
|
||||
return
|
||||
}
|
||||
|
||||
// fmt.Println("processes: ", processes)
|
||||
|
||||
printHeaders()
|
||||
for _, process := range processes {
|
||||
// fmt.Println(i + 1)
|
||||
|
||||
printResultOfKeyword(process)
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
printHeaders()
|
||||
printResultOfKeyword(os.Args[1])
|
||||
|
||||
if len(os.Args) >= 3 {
|
||||
seconds, err := strconv.ParseFloat(os.Args[2], 64)
|
||||
if err != nil || seconds <= 0 {
|
||||
fmt.Fprintf(os.Stderr, "invalid interval: %s\n", os.Args[2])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
ProcessCount int
|
||||
CPUPercent float64
|
||||
RAMBytes uint64
|
||||
SwapBytes uint64
|
||||
}
|
||||
|
||||
func calculate(first, second Snapshot, cpuCount uint64) Result {
|
||||
var result Result
|
||||
|
||||
// RAM and swap are taken from the second snapshot.
|
||||
for _, p := range second.Processes {
|
||||
result.ProcessCount++
|
||||
|
||||
result.RAMBytes += pagesToBytes(p.RSSPages)
|
||||
result.SwapBytes += p.SwapBytes
|
||||
}
|
||||
|
||||
/*
|
||||
CPU calculation:
|
||||
|
||||
Process CPU time is measured in clock ticks.
|
||||
|
||||
We calculate:
|
||||
|
||||
process_delta / total_cpu_delta * number_of_cpus * 100
|
||||
|
||||
This allows CPU usage to exceed 100% when a process/group
|
||||
is using multiple cores.
|
||||
*/
|
||||
|
||||
var processDelta uint64
|
||||
|
||||
for pid, secondProcess := range second.Processes {
|
||||
firstProcess, exists := first.Processes[pid]
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
|
||||
if secondProcess.CPUTime >= firstProcess.CPUTime {
|
||||
processDelta += secondProcess.CPUTime - firstProcess.CPUTime
|
||||
}
|
||||
}
|
||||
|
||||
totalCPUDelta := second.TotalCPU - first.TotalCPU
|
||||
|
||||
if totalCPUDelta > 0 {
|
||||
// result.CPUPercent =
|
||||
// (float64(processDelta) / float64(totalCPUDelta)) *
|
||||
// float64(cpuCount) *
|
||||
// 100
|
||||
|
||||
// so instead of cpu percentage being 200% or something it will only be relative to 100%
|
||||
result.CPUPercent =
|
||||
(float64(processDelta) / float64(totalCPUDelta)) * 100
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func takeSnapshot(keyword string) (Snapshot, error) {
|
||||
snapshot := Snapshot{
|
||||
Processes: make(map[int]Process),
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir("/proc")
|
||||
if err != nil {
|
||||
return snapshot, err
|
||||
}
|
||||
|
||||
selfPID := os.Getpid()
|
||||
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
pid, err := strconv.Atoi(entry.Name())
|
||||
if err != nil {
|
||||
// Not a PID directory.
|
||||
continue
|
||||
}
|
||||
|
||||
// Don't count procusage itself.
|
||||
if pid == selfPID {
|
||||
continue
|
||||
}
|
||||
|
||||
process, err := readProcess(pid)
|
||||
if err != nil {
|
||||
// Process may have exited between ReadDir and reading
|
||||
// /proc/<pid>. That's normal.
|
||||
continue
|
||||
}
|
||||
|
||||
commandLower := strings.ToLower(process.Command)
|
||||
|
||||
if strings.Contains(commandLower, keyword) {
|
||||
snapshot.Processes[pid] = process
|
||||
}
|
||||
}
|
||||
|
||||
snapshot.TotalCPU, _ = readTotalCPU()
|
||||
|
||||
return snapshot, nil
|
||||
}
|
||||
|
||||
func readProcess(pid int) (Process, error) {
|
||||
var process Process
|
||||
|
||||
process.PID = pid
|
||||
|
||||
// Read the complete command line.
|
||||
cmdline, err := os.ReadFile(
|
||||
filepath.Join("/proc", strconv.Itoa(pid), "cmdline"),
|
||||
)
|
||||
if err != nil {
|
||||
return process, err
|
||||
}
|
||||
|
||||
/*
|
||||
/proc/<pid>/cmdline is separated by NUL bytes:
|
||||
|
||||
/usr/bin/firefox\0--some-option\0foo\0
|
||||
|
||||
Convert those NULs into spaces so matching and displaying
|
||||
the command line is convenient.
|
||||
*/
|
||||
command := strings.ReplaceAll(string(cmdline), "\x00", " ")
|
||||
command = strings.TrimSpace(command)
|
||||
|
||||
// Some kernel/system processes have an empty cmdline.
|
||||
// Fall back to /comm if necessary.
|
||||
if command == "" {
|
||||
comm, err := os.ReadFile(
|
||||
filepath.Join("/proc", strconv.Itoa(pid), "comm"),
|
||||
)
|
||||
if err != nil {
|
||||
return process, err
|
||||
}
|
||||
|
||||
command = strings.TrimSpace(string(comm))
|
||||
}
|
||||
|
||||
process.Command = command
|
||||
|
||||
// CPU time from /proc/<pid>/stat.
|
||||
cpuTime, rssPages, err := readStat(pid)
|
||||
if err != nil {
|
||||
return process, err
|
||||
}
|
||||
|
||||
process.CPUTime = cpuTime
|
||||
process.RSSPages = rssPages
|
||||
|
||||
// Swap from /proc/<pid>/status.
|
||||
process.SwapBytes = readSwap(pid)
|
||||
|
||||
return process, nil
|
||||
}
|
||||
|
||||
func readStat(pid int) (cpuTime uint64, rssPages uint64, err error) {
|
||||
path := filepath.Join("/proc", strconv.Itoa(pid), "stat")
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
line := string(data)
|
||||
|
||||
/*
|
||||
/proc/<pid>/stat contains:
|
||||
|
||||
pid (comm) state ppid ...
|
||||
|
||||
The comm field itself can contain spaces and parentheses,
|
||||
so we cannot simply strings.Fields() the whole line.
|
||||
|
||||
Find the LAST ')' which terminates comm.
|
||||
*/
|
||||
closeParen := strings.LastIndex(line, ")")
|
||||
if closeParen == -1 {
|
||||
return 0, 0, errors.New("invalid /proc/stat format")
|
||||
}
|
||||
|
||||
rest := strings.TrimSpace(line[closeParen+1:])
|
||||
fields := strings.Fields(rest)
|
||||
|
||||
/*
|
||||
After comm, fields start at:
|
||||
|
||||
field 3 = state
|
||||
field 4 = ppid
|
||||
...
|
||||
field 14 = utime
|
||||
field 15 = stime
|
||||
...
|
||||
field 24 = rss
|
||||
|
||||
Because fields[] starts at field 3:
|
||||
|
||||
utime -> index 11
|
||||
stime -> index 12
|
||||
rss -> index 21
|
||||
*/
|
||||
|
||||
if len(fields) <= 21 {
|
||||
return 0, 0, errors.New("short /proc/stat entry")
|
||||
}
|
||||
|
||||
utime, err := strconv.ParseUint(fields[11], 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
stime, err := strconv.ParseUint(fields[12], 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
rss, err := strconv.ParseInt(fields[21], 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
if rss < 0 {
|
||||
rss = 0
|
||||
}
|
||||
|
||||
return utime + stime, uint64(rss), nil
|
||||
}
|
||||
|
||||
func readSwap(pid int) uint64 {
|
||||
path := filepath.Join("/proc", strconv.Itoa(pid), "status")
|
||||
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
||||
if !strings.HasPrefix(line, "VmSwap:") {
|
||||
continue
|
||||
}
|
||||
|
||||
fields := strings.Fields(line)
|
||||
|
||||
if len(fields) < 2 {
|
||||
return 0
|
||||
}
|
||||
|
||||
/*
|
||||
VmSwap is normally reported in kB.
|
||||
*/
|
||||
kb, err := strconv.ParseUint(fields[1], 10, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return kb * 1024
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func readTotalCPU() (uint64, error) {
|
||||
data, err := os.ReadFile("/proc/stat")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(strings.NewReader(string(data)))
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
||||
if !strings.HasPrefix(line, "cpu ") {
|
||||
continue
|
||||
}
|
||||
|
||||
fields := strings.Fields(line)
|
||||
|
||||
if len(fields) < 2 {
|
||||
return 0, errors.New("invalid /proc/stat cpu line")
|
||||
}
|
||||
|
||||
var total uint64
|
||||
|
||||
for _, field := range fields[1:] {
|
||||
value, err := strconv.ParseUint(field, 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
total += value
|
||||
}
|
||||
|
||||
return total, nil
|
||||
}
|
||||
|
||||
return 0, errors.New("cpu line not found")
|
||||
}
|
||||
|
||||
func pagesToBytes(pages uint64) uint64 {
|
||||
pageSize := uint64(os.Getpagesize())
|
||||
return pages * pageSize
|
||||
}
|
||||
|
||||
func getCPUCount() int {
|
||||
count := os.Getenv("NUMBER_OF_PROCESSORS")
|
||||
|
||||
if count != "" {
|
||||
if n, err := strconv.Atoi(count); err == nil && n > 0 {
|
||||
return n
|
||||
}
|
||||
}
|
||||
|
||||
// Linux: use /proc/cpuinfo.
|
||||
file, err := os.Open("/proc/cpuinfo")
|
||||
if err != nil {
|
||||
return 1
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
cpus := 0
|
||||
|
||||
for scanner.Scan() {
|
||||
if strings.HasPrefix(scanner.Text(), "processor") {
|
||||
cpus++
|
||||
}
|
||||
}
|
||||
|
||||
if cpus == 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
return cpus
|
||||
}
|
||||
|
||||
func printHeaders() {
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", "Name", "Processes", "CPU", "RAM", "Swap")
|
||||
}
|
||||
|
||||
func printResult(keyword string, result Result) {
|
||||
|
||||
// fmt.Printf("%s\n", keyword)
|
||||
// fmt.Printf(" Processes : %d\n", result.ProcessCount)
|
||||
// fmt.Printf(" CPU : %.1f%%\n", result.CPUPercent)
|
||||
// fmt.Printf(" RAM : %s\n", formatBytes(result.RAMBytes))
|
||||
// fmt.Printf(" Swap : %s\n", formatBytes(result.SwapBytes))
|
||||
// fmt.Printf("\n")
|
||||
// fmt.Printf("\n")
|
||||
|
||||
fmt.Fprintf(w, "%s\t%d\t%.1f\t%s\t%s\n", keyword, result.ProcessCount, result.CPUPercent, formatBytes(result.RAMBytes), formatBytes(result.SwapBytes))
|
||||
|
||||
}
|
||||
|
||||
func formatBytes(bytes uint64) string {
|
||||
const (
|
||||
KB = 1024
|
||||
MB = 1024 * KB
|
||||
GB = 1024 * MB
|
||||
)
|
||||
|
||||
switch {
|
||||
case bytes >= GB:
|
||||
return fmt.Sprintf("%.2f GB", float64(bytes)/float64(GB))
|
||||
|
||||
case bytes >= MB:
|
||||
return fmt.Sprintf("%.0f MB", float64(bytes)/float64(MB))
|
||||
|
||||
case bytes >= KB:
|
||||
return fmt.Sprintf("%.0f KB", float64(bytes)/float64(KB))
|
||||
|
||||
default:
|
||||
return fmt.Sprintf("%d B", bytes)
|
||||
}
|
||||
}
|
||||
448
_resources/main.go
Normal file
|
|
@ -0,0 +1,448 @@
|
|||
//go:build linux
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Process struct {
|
||||
PID int
|
||||
Command string
|
||||
CPUTime uint64 // clock ticks
|
||||
RSSPages uint64
|
||||
SwapBytes uint64
|
||||
}
|
||||
|
||||
type Snapshot struct {
|
||||
Processes map[int]Process
|
||||
TotalCPU uint64
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
fmt.Printf("Usage: %s <keyword> [interval]\n", os.Args[0])
|
||||
fmt.Printf("\nExamples:\n")
|
||||
fmt.Printf(" %s firefox\n", os.Args[0])
|
||||
fmt.Printf(" %s firefox 1\n", os.Args[0])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
keyword := strings.ToLower(os.Args[1])
|
||||
|
||||
interval := time.Second
|
||||
|
||||
if len(os.Args) >= 3 {
|
||||
seconds, err := strconv.ParseFloat(os.Args[2], 64)
|
||||
if err != nil || seconds <= 0 {
|
||||
fmt.Fprintf(os.Stderr, "invalid interval: %s\n", os.Args[2])
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
interval = time.Duration(seconds * float64(time.Second))
|
||||
}
|
||||
|
||||
numCPU := uint64(os.Getuid()) // replaced below
|
||||
_ = numCPU
|
||||
|
||||
cpuCount := uint64(getCPUCount())
|
||||
|
||||
if cpuCount == 0 {
|
||||
cpuCount = 1
|
||||
}
|
||||
|
||||
// First snapshot.
|
||||
first, err := takeSnapshot(keyword)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "snapshot error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
time.Sleep(interval)
|
||||
|
||||
// Second snapshot.
|
||||
second, err := takeSnapshot(keyword)
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "snapshot error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
result := calculate(first, second, cpuCount)
|
||||
|
||||
printResult(keyword, result)
|
||||
}
|
||||
|
||||
type Result struct {
|
||||
ProcessCount int
|
||||
CPUPercent float64
|
||||
RAMBytes uint64
|
||||
SwapBytes uint64
|
||||
}
|
||||
|
||||
func calculate(first, second Snapshot, cpuCount uint64) Result {
|
||||
var result Result
|
||||
|
||||
// RAM and swap are taken from the second snapshot.
|
||||
for _, p := range second.Processes {
|
||||
result.ProcessCount++
|
||||
|
||||
result.RAMBytes += pagesToBytes(p.RSSPages)
|
||||
result.SwapBytes += p.SwapBytes
|
||||
}
|
||||
|
||||
/*
|
||||
CPU calculation:
|
||||
|
||||
Process CPU time is measured in clock ticks.
|
||||
|
||||
We calculate:
|
||||
|
||||
process_delta / total_cpu_delta * number_of_cpus * 100
|
||||
|
||||
This allows CPU usage to exceed 100% when a process/group
|
||||
is using multiple cores.
|
||||
*/
|
||||
|
||||
var processDelta uint64
|
||||
|
||||
for pid, secondProcess := range second.Processes {
|
||||
firstProcess, exists := first.Processes[pid]
|
||||
if !exists {
|
||||
continue
|
||||
}
|
||||
|
||||
if secondProcess.CPUTime >= firstProcess.CPUTime {
|
||||
processDelta += secondProcess.CPUTime - firstProcess.CPUTime
|
||||
}
|
||||
}
|
||||
|
||||
totalCPUDelta := second.TotalCPU - first.TotalCPU
|
||||
|
||||
if totalCPUDelta > 0 {
|
||||
result.CPUPercent =
|
||||
(float64(processDelta) / float64(totalCPUDelta)) *
|
||||
float64(cpuCount) *
|
||||
100
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func takeSnapshot(keyword string) (Snapshot, error) {
|
||||
snapshot := Snapshot{
|
||||
Processes: make(map[int]Process),
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir("/proc")
|
||||
if err != nil {
|
||||
return snapshot, err
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
pid, err := strconv.Atoi(entry.Name())
|
||||
if err != nil {
|
||||
// Not a PID directory.
|
||||
continue
|
||||
}
|
||||
|
||||
process, err := readProcess(pid)
|
||||
if err != nil {
|
||||
// Process may have exited between ReadDir and reading
|
||||
// /proc/<pid>. That's normal.
|
||||
continue
|
||||
}
|
||||
|
||||
commandLower := strings.ToLower(process.Command)
|
||||
|
||||
if strings.Contains(commandLower, keyword) {
|
||||
snapshot.Processes[pid] = process
|
||||
}
|
||||
}
|
||||
|
||||
snapshot.TotalCPU, _ = readTotalCPU()
|
||||
|
||||
return snapshot, nil
|
||||
}
|
||||
|
||||
func readProcess(pid int) (Process, error) {
|
||||
var process Process
|
||||
|
||||
process.PID = pid
|
||||
|
||||
// Read the complete command line.
|
||||
cmdline, err := os.ReadFile(
|
||||
filepath.Join("/proc", strconv.Itoa(pid), "cmdline"),
|
||||
)
|
||||
if err != nil {
|
||||
return process, err
|
||||
}
|
||||
|
||||
/*
|
||||
/proc/<pid>/cmdline is separated by NUL bytes:
|
||||
|
||||
/usr/bin/firefox\0--some-option\0foo\0
|
||||
|
||||
Convert those NULs into spaces so matching and displaying
|
||||
the command line is convenient.
|
||||
*/
|
||||
command := strings.ReplaceAll(string(cmdline), "\x00", " ")
|
||||
command = strings.TrimSpace(command)
|
||||
|
||||
// Some kernel/system processes have an empty cmdline.
|
||||
// Fall back to /comm if necessary.
|
||||
if command == "" {
|
||||
comm, err := os.ReadFile(
|
||||
filepath.Join("/proc", strconv.Itoa(pid), "comm"),
|
||||
)
|
||||
if err != nil {
|
||||
return process, err
|
||||
}
|
||||
|
||||
command = strings.TrimSpace(string(comm))
|
||||
}
|
||||
|
||||
process.Command = command
|
||||
|
||||
// CPU time from /proc/<pid>/stat.
|
||||
cpuTime, rssPages, err := readStat(pid)
|
||||
if err != nil {
|
||||
return process, err
|
||||
}
|
||||
|
||||
process.CPUTime = cpuTime
|
||||
process.RSSPages = rssPages
|
||||
|
||||
// Swap from /proc/<pid>/status.
|
||||
process.SwapBytes = readSwap(pid)
|
||||
|
||||
return process, nil
|
||||
}
|
||||
|
||||
func readStat(pid int) (cpuTime uint64, rssPages uint64, err error) {
|
||||
path := filepath.Join("/proc", strconv.Itoa(pid), "stat")
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
line := string(data)
|
||||
|
||||
/*
|
||||
/proc/<pid>/stat contains:
|
||||
|
||||
pid (comm) state ppid ...
|
||||
|
||||
The comm field itself can contain spaces and parentheses,
|
||||
so we cannot simply strings.Fields() the whole line.
|
||||
|
||||
Find the LAST ')' which terminates comm.
|
||||
*/
|
||||
closeParen := strings.LastIndex(line, ")")
|
||||
if closeParen == -1 {
|
||||
return 0, 0, errors.New("invalid /proc/stat format")
|
||||
}
|
||||
|
||||
rest := strings.TrimSpace(line[closeParen+1:])
|
||||
fields := strings.Fields(rest)
|
||||
|
||||
/*
|
||||
After comm, fields start at:
|
||||
|
||||
field 3 = state
|
||||
field 4 = ppid
|
||||
...
|
||||
field 14 = utime
|
||||
field 15 = stime
|
||||
...
|
||||
field 24 = rss
|
||||
|
||||
Because fields[] starts at field 3:
|
||||
|
||||
utime -> index 11
|
||||
stime -> index 12
|
||||
rss -> index 21
|
||||
*/
|
||||
|
||||
if len(fields) <= 21 {
|
||||
return 0, 0, errors.New("short /proc/stat entry")
|
||||
}
|
||||
|
||||
utime, err := strconv.ParseUint(fields[11], 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
stime, err := strconv.ParseUint(fields[12], 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
rss, err := strconv.ParseInt(fields[21], 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
if rss < 0 {
|
||||
rss = 0
|
||||
}
|
||||
|
||||
return utime + stime, uint64(rss), nil
|
||||
}
|
||||
|
||||
func readSwap(pid int) uint64 {
|
||||
path := filepath.Join("/proc", strconv.Itoa(pid), "status")
|
||||
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
||||
if !strings.HasPrefix(line, "VmSwap:") {
|
||||
continue
|
||||
}
|
||||
|
||||
fields := strings.Fields(line)
|
||||
|
||||
if len(fields) < 2 {
|
||||
return 0
|
||||
}
|
||||
|
||||
/*
|
||||
VmSwap is normally reported in kB.
|
||||
*/
|
||||
kb, err := strconv.ParseUint(fields[1], 10, 64)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
return kb * 1024
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func readTotalCPU() (uint64, error) {
|
||||
data, err := os.ReadFile("/proc/stat")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(strings.NewReader(string(data)))
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
|
||||
if !strings.HasPrefix(line, "cpu ") {
|
||||
continue
|
||||
}
|
||||
|
||||
fields := strings.Fields(line)
|
||||
|
||||
if len(fields) < 2 {
|
||||
return 0, errors.New("invalid /proc/stat cpu line")
|
||||
}
|
||||
|
||||
var total uint64
|
||||
|
||||
for _, field := range fields[1:] {
|
||||
value, err := strconv.ParseUint(field, 10, 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
total += value
|
||||
}
|
||||
|
||||
return total, nil
|
||||
}
|
||||
|
||||
return 0, errors.New("cpu line not found")
|
||||
}
|
||||
|
||||
func pagesToBytes(pages uint64) uint64 {
|
||||
pageSize := uint64(os.Getpagesize())
|
||||
return pages * pageSize
|
||||
}
|
||||
|
||||
func getCPUCount() int {
|
||||
count := os.Getenv("NUMBER_OF_PROCESSORS")
|
||||
|
||||
if count != "" {
|
||||
if n, err := strconv.Atoi(count); err == nil && n > 0 {
|
||||
return n
|
||||
}
|
||||
}
|
||||
|
||||
// Linux: use /proc/cpuinfo.
|
||||
file, err := os.Open("/proc/cpuinfo")
|
||||
if err != nil {
|
||||
return 1
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
cpus := 0
|
||||
|
||||
for scanner.Scan() {
|
||||
if strings.HasPrefix(scanner.Text(), "processor") {
|
||||
cpus++
|
||||
}
|
||||
}
|
||||
|
||||
if cpus == 0 {
|
||||
return 1
|
||||
}
|
||||
|
||||
return cpus
|
||||
}
|
||||
|
||||
func printResult(keyword string, result Result) {
|
||||
fmt.Printf("\n")
|
||||
fmt.Printf("%s\n", keyword)
|
||||
fmt.Printf(" Processes : %d\n", result.ProcessCount)
|
||||
fmt.Printf(" CPU : %.1f%%\n", result.CPUPercent)
|
||||
fmt.Printf(" RAM : %s\n", formatBytes(result.RAMBytes))
|
||||
fmt.Printf(" Swap : %s\n", formatBytes(result.SwapBytes))
|
||||
fmt.Printf("\n")
|
||||
}
|
||||
|
||||
func formatBytes(bytes uint64) string {
|
||||
const (
|
||||
KB = 1024
|
||||
MB = 1024 * KB
|
||||
GB = 1024 * MB
|
||||
)
|
||||
|
||||
switch {
|
||||
case bytes >= GB:
|
||||
return fmt.Sprintf("%.2f GB", float64(bytes)/float64(GB))
|
||||
|
||||
case bytes >= MB:
|
||||
return fmt.Sprintf("%.0f MB", float64(bytes)/float64(MB))
|
||||
|
||||
case bytes >= KB:
|
||||
return fmt.Sprintf("%.0f KB", float64(bytes)/float64(KB))
|
||||
|
||||
default:
|
||||
return fmt.Sprintf("%d B", bytes)
|
||||
}
|
||||
}
|
||||
119
_resources/main1.sh
Executable file
|
|
@ -0,0 +1,119 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -u
|
||||
|
||||
KEYWORD="${1:-}"
|
||||
KEYWORD_LOWER="${KEYWORD,,}"
|
||||
|
||||
if [[ -z "$KEYWORD" ]]; then
|
||||
echo "Usage: $0 <keyword>"
|
||||
echo
|
||||
echo "Examples:"
|
||||
echo " $0 firefox"
|
||||
echo " $0 chrome"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TOTAL_CPU=0
|
||||
TOTAL_RAM_KB=0
|
||||
TOTAL_SWAP_KB=0
|
||||
PROCESS_COUNT=0
|
||||
|
||||
# ps aux:
|
||||
#
|
||||
# USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
|
||||
#
|
||||
# We skip the header and inspect:
|
||||
#
|
||||
# $2 = PID
|
||||
# $3 = CPU
|
||||
# $6 = RSS
|
||||
# $11 onward = COMMAND
|
||||
#
|
||||
# Using "read -ra" would lose command boundaries, so we use awk
|
||||
# to print the first 10 fields plus the complete command.
|
||||
|
||||
while read -r pid cpu rss command; do
|
||||
|
||||
[[ -n "$pid" ]] || continue
|
||||
|
||||
# Case-insensitive matching against the complete command.
|
||||
if [[ "${command,,}" != *"$KEYWORD_LOWER"* ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
PROCESS_COUNT=$((PROCESS_COUNT + 1))
|
||||
|
||||
# CPU percentage from ps.
|
||||
TOTAL_CPU=$(awk \
|
||||
-v a="$TOTAL_CPU" \
|
||||
-v b="$cpu" \
|
||||
'BEGIN { printf "%.2f", a + b }')
|
||||
|
||||
# RSS is in KB.
|
||||
TOTAL_RAM_KB=$((TOTAL_RAM_KB + rss))
|
||||
|
||||
# VmSwap is in kB.
|
||||
if [[ -r "/proc/$pid/status" ]]; then
|
||||
swap=$(awk '
|
||||
/^VmSwap:/ {
|
||||
print $2
|
||||
found=1
|
||||
exit
|
||||
}
|
||||
END {
|
||||
if (!found)
|
||||
print 0
|
||||
}
|
||||
' "/proc/$pid/status" 2>/dev/null)
|
||||
|
||||
[[ "$swap" =~ ^[0-9]+$ ]] || swap=0
|
||||
|
||||
TOTAL_SWAP_KB=$((TOTAL_SWAP_KB + swap))
|
||||
fi
|
||||
|
||||
done < <(
|
||||
ps aux |
|
||||
tail -n +2 |
|
||||
awk '
|
||||
{
|
||||
pid=$2
|
||||
cpu=$3
|
||||
rss=$6
|
||||
|
||||
command=""
|
||||
for (i=11; i<=NF; i++) {
|
||||
command = command (i==11 ? "" : " ") $i
|
||||
}
|
||||
|
||||
print pid, cpu, rss, command
|
||||
}'
|
||||
)
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# Format KB
|
||||
# ------------------------------------------------------------
|
||||
|
||||
format_kb() {
|
||||
local kb="$1"
|
||||
|
||||
if (( kb >= 1024 * 1024 )); then
|
||||
awk -v kb="$kb" \
|
||||
'BEGIN { printf "%.2f GB", kb / 1024 / 1024 }'
|
||||
|
||||
elif (( kb >= 1024 )); then
|
||||
awk -v kb="$kb" \
|
||||
'BEGIN { printf "%.0f MB", kb / 1024 }'
|
||||
|
||||
else
|
||||
printf "%d KB" "$kb"
|
||||
fi
|
||||
}
|
||||
|
||||
echo
|
||||
echo "$KEYWORD"
|
||||
echo " Processes : $PROCESS_COUNT"
|
||||
printf " CPU : %.2f%%\n" "$TOTAL_CPU"
|
||||
echo " RAM : $(format_kb "$TOTAL_RAM_KB")"
|
||||
echo " Swap : $(format_kb "$TOTAL_SWAP_KB")"
|
||||
echo
|
||||
BIN
_resources/media_kit_ex.zip
Normal file
BIN
_resources/memreduct-3.4-bin.zip
Normal file
BIN
_resources/mrmlnc.vscode-scss-0.10.0.7z
Normal file
BIN
_resources/mrrefactoring.polacode-fixed-edition-0.3.6.7z
Normal file
BIN
_resources/naumovs.theme-oceanicnext-0.0.4.7z
Normal file
4387
_resources/netlog.txt
Normal file
BIN
_resources/neutralinojs-main.zip
Normal file
107
_resources/nginx.md
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
To serve your `index.html` file using Nginx on Arch Linux, you need to follow a few simple steps for installation, configuration, and starting the web server. This guide is meant to help you get started.
|
||||
|
||||
### Step 1: Installing Nginx
|
||||
|
||||
1. **Open your Terminal.**
|
||||
|
||||
2. **Update your system package database** by running:
|
||||
```
|
||||
sudo pacman -Syu
|
||||
```
|
||||
3. **Install Nginx** with the following command:
|
||||
```
|
||||
sudo pacman -S nginx
|
||||
```
|
||||
|
||||
### Step 2: Configuring Nginx to Serve Your HTML File
|
||||
|
||||
1. **Navigate to the Nginx configuration directory:**
|
||||
```
|
||||
cd /etc/nginx
|
||||
```
|
||||
|
||||
2. The main configuration file is `/etc/nginx/nginx.conf`, but for hosting specific sites, it's a good practice to use the `sites-available` and `sites-enabled` structure, which might not be set up by default on Arch. Let's create those directories:
|
||||
```
|
||||
sudo mkdir sites-available
|
||||
sudo mkdir sites-enabled
|
||||
```
|
||||
|
||||
3. Add the following line to the bottom of the `nginx.conf` file to include the `sites-enabled` directory. You can open it with your favorite text editor, for example:
|
||||
```
|
||||
sudo nano nginx.conf
|
||||
```
|
||||
At the bottom of the file, add:
|
||||
```
|
||||
include /etc/nginx/sites-enabled/*;
|
||||
```
|
||||
Then save and close the file.
|
||||
|
||||
4. **Create a new configuration file** for your site in the `sites-available` directory. Replace `yourdomain.com` with your domain name or `localhost` if you don’t have one:
|
||||
```
|
||||
sudo nano sites-available/yourdomain.com
|
||||
```
|
||||
|
||||
5. Add the following server block (adjust the `server_name` if using a domain, and change `/path/to/your/index.html` to the actual path of your `index.html` file):
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name yourdomain.com; # Or localhost
|
||||
location / {
|
||||
root /path/to/your;
|
||||
index index.html;
|
||||
}
|
||||
}
|
||||
```
|
||||
Save and close the file.
|
||||
|
||||
6. **Create a symbolic link** to enable the site:
|
||||
```
|
||||
sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/
|
||||
```
|
||||
|
||||
### Step 3: Starting Nginx
|
||||
|
||||
1. **Start the Nginx service** with the following command:
|
||||
```
|
||||
sudo systemctl start nginx
|
||||
```
|
||||
|
||||
2. **Enable Nginx to start at boot:**
|
||||
```
|
||||
sudo systemctl enable nginx
|
||||
```
|
||||
|
||||
### Step 4: Adjusting the Firewall
|
||||
|
||||
If you have a firewall enabled (like `ufw` or `firewalld`), you need to allow HTTP traffic:
|
||||
|
||||
- For `ufw`:
|
||||
```
|
||||
sudo ufw allow 'Nginx Full'
|
||||
sudo ufw reload
|
||||
```
|
||||
|
||||
- For `firewalld`:
|
||||
```
|
||||
sudo firewall-cmd --add-service=http --permanent
|
||||
sudo firewall-cmd --reload
|
||||
```
|
||||
|
||||
### Step 5: Accessing Your Website
|
||||
|
||||
Now, open a browser and go to `http://yourdomain.com` or `http://localhost` if you didn’t set up a domain. You should see your `index.html` page served by Nginx.
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
- If Nginx fails to start or reload, you can check the error messages with:
|
||||
```
|
||||
sudo systemctl status nginx
|
||||
```
|
||||
or
|
||||
```
|
||||
sudo journalctl -xeu nginx
|
||||
```
|
||||
|
||||
- Ensure the `server_name` and the path to your `index.html` are correctly specified in your Nginx site configuration.
|
||||
|
||||
Congratulations, you have now set up Nginx to serve your HTML page on Arch Linux!
|
||||
BIN
_resources/node-gyp-9.4.0-1-any.pkg.tar.zst
Normal file
BIN
_resources/node-gyp-9.4.0-1-any.pkg.tar.zst.sig
Normal file
BIN
_resources/nodejs-20.8.0-1-x86_64.pkg.tar.zst
Normal file
BIN
_resources/nodejs-20.8.0-1-x86_64.pkg.tar.zst.sig
Normal file
BIN
_resources/nodejs-nopt-7.2.0-1-any.pkg.tar.zst
Normal file
BIN
_resources/nodejs-nopt-7.2.0-1-any.pkg.tar.zst.sig
Normal file
BIN
_resources/nopaste-master.zip
Normal file
BIN
_resources/notion-lock-main.zip
Normal file
BIN
_resources/npm-10.2.0-1-any.pkg.tar.zst
Normal file
BIN
_resources/npm-10.2.0-1-any.pkg.tar.zst.sig
Normal file
BIN
_resources/nvim.zip
Normal file
46
_resources/parsing_with_new.dart
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import 'package:html/parser.dart' as html_parser; // To parse the HTML
|
||||
import 'package:html/dom.dart'; // For working with the DOM structure
|
||||
|
||||
void main() {
|
||||
// Example HTML content with some nested tags
|
||||
String htmlContent = '''
|
||||
<div>
|
||||
Line 1<br>
|
||||
<div>Line 2<br>Line 3<br><span>Nested Line 4</span></div>
|
||||
Line 5
|
||||
</div>
|
||||
''';
|
||||
|
||||
// Parse the HTML content
|
||||
Document document = html_parser.parse(htmlContent);
|
||||
|
||||
// Find the desired element
|
||||
Element? divElement = document.querySelector('div');
|
||||
|
||||
if (divElement != null) {
|
||||
// Extract and preserve newlines recursively
|
||||
String preservedText = preserveTextWithNewlines(divElement);
|
||||
print(preservedText);
|
||||
}
|
||||
}
|
||||
|
||||
String preserveTextWithNewlines(Element element) {
|
||||
final buffer = StringBuffer();
|
||||
|
||||
for (var node in element.nodes) {
|
||||
if (node is Text) {
|
||||
// Append text content
|
||||
buffer.write(node.text);
|
||||
} else if (node is Element) {
|
||||
if (node.localName == 'br') {
|
||||
// Add newline for <br> tags
|
||||
buffer.write('\n');
|
||||
} else {
|
||||
// Recursively process child elements
|
||||
buffer.write(preserveTextWithNewlines(node));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
BIN
_resources/pkief.material-icon-theme-4.22.0.7z
Normal file
101
_resources/popupmenu.dart
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
enum Options { search, upload, copy, exit }
|
||||
|
||||
void main() {
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatefulWidget {
|
||||
const MyApp({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<MyApp> createState() => _MyAppState();
|
||||
}
|
||||
|
||||
class _MyAppState extends State<MyApp> {
|
||||
var _popupMenuItemIndex = 0;
|
||||
Color _changeColorAccordingToMenuItem = Colors.red;
|
||||
var appBarHeight = AppBar().preferredSize.height;
|
||||
|
||||
_buildAppBar() {
|
||||
return AppBar(
|
||||
title: const Text(
|
||||
'Popup Menus',
|
||||
style: TextStyle(color: Colors.white, fontSize: 16.0),
|
||||
),
|
||||
actions: [
|
||||
PopupMenuButton(
|
||||
onSelected: (value) {
|
||||
_onMenuItemSelected(value as int);
|
||||
},
|
||||
offset: Offset(0.0, appBarHeight),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(8.0),
|
||||
bottomRight: Radius.circular(8.0),
|
||||
topLeft: Radius.circular(8.0),
|
||||
topRight: Radius.circular(8.0),
|
||||
),
|
||||
),
|
||||
itemBuilder: (ctx) => [
|
||||
_buildPopupMenuItem('Search', Icons.search, Options.search.index),
|
||||
_buildPopupMenuItem('Upload', Icons.upload, Options.upload.index),
|
||||
_buildPopupMenuItem('Copy', Icons.copy, Options.copy.index),
|
||||
_buildPopupMenuItem('Exit', Icons.exit_to_app, Options.exit.index),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
PopupMenuItem _buildPopupMenuItem(
|
||||
String title, IconData iconData, int position) {
|
||||
return PopupMenuItem(
|
||||
value: position,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Icon(
|
||||
iconData,
|
||||
color: Colors.black,
|
||||
),
|
||||
Text(title),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_onMenuItemSelected(int value) {
|
||||
setState(() {
|
||||
_popupMenuItemIndex = value;
|
||||
});
|
||||
|
||||
if (value == Options.search.index) {
|
||||
_changeColorAccordingToMenuItem = Colors.red;
|
||||
} else if (value == Options.upload.index) {
|
||||
_changeColorAccordingToMenuItem = Colors.green;
|
||||
} else if (value == Options.copy.index) {
|
||||
_changeColorAccordingToMenuItem = Colors.blue;
|
||||
} else {
|
||||
_changeColorAccordingToMenuItem = Colors.purple;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'Flutter Demo',
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ThemeData(
|
||||
primarySwatch: Colors.blue,
|
||||
),
|
||||
home: Scaffold(
|
||||
appBar: _buildAppBar(),
|
||||
// body: Container(
|
||||
// color: _changeColorAccordingToMenuItem,
|
||||
// ),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
BIN
_resources/pranaygp.vscode-css-peek-4.2.0.7z
Normal file
BIN
_resources/protonvpn-1.0.0-3-any.pkg.tar.zst
Normal file
BIN
_resources/protonvpn-cli-3.13.0-2-any.pkg.tar.zst
Normal file
BIN
_resources/protonvpn-gui-1.12.0-1-any.pkg.tar.zst
Normal file
BIN
_resources/rarlinux-x64-623.tar.gz
Normal file
BIN
_resources/react-drop-file-input-main.zip
Normal file
BIN
_resources/react.zip
Normal file
BIN
_resources/redis-7.2.1-1-x86_64.pkg.tar.zst
Normal file
BIN
_resources/redis-7.2.1-1-x86_64.pkg.tar.zst.sig
Normal file
62
_resources/rightclick_simulation.dart
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
As I mentioned before, directly detecting right-clicks in Flutter isn't natively supported due to its touch-centric nature. However, there are ways to achieve similar functionality, especially on desktop platforms.
|
||||
|
||||
Let's explore the options with more detail and code examples:
|
||||
|
||||
1. Long Press (Cross-Platform, but not true right-click):
|
||||
|
||||
This is the most straightforward and cross-platform approach. It uses a long press gesture to trigger an action that mimics a right-click.
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class RightClickSimulation extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onLongPress: () {
|
||||
_showContextMenu(context);
|
||||
},
|
||||
child: Container(
|
||||
width: 200,
|
||||
height: 100,
|
||||
color: Colors.lightBlue,
|
||||
child: Center(
|
||||
child: Text('Long Press for Context Menu'),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showContextMenu(BuildContext context) async {
|
||||
final RenderBox renderBox = context.findRenderObject() as RenderBox;
|
||||
final position = renderBox.localToGlobal(Offset.zero);
|
||||
|
||||
final selectedItem = await showMenu(
|
||||
context: context,
|
||||
position: RelativeRect.fromLTRB(
|
||||
position.dx,
|
||||
position.dy + renderBox.size.height,
|
||||
position.dx + renderBox.size.width,
|
||||
position.dy + 2 * renderBox.size.height,
|
||||
),
|
||||
items: [
|
||||
PopupMenuItem(
|
||||
value: 'option1',
|
||||
child: Text('Option 1'),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: 'option2',
|
||||
child: Text('Option 2'),
|
||||
),
|
||||
PopupMenuItem(
|
||||
value: 'option3',
|
||||
child: Text('Option 3'),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
if (selectedItem != null) {
|
||||
print('Selected: $selectedItem');
|
||||
// Handle the selected option here
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
_resources/ritwickdey.live-sass-3.0.0.7z
Normal file
BIN
_resources/ritwickdey.liveserver-5.7.9.7z
Normal file
|
After Width: | Height: | Size: 519 KiB |
98
_resources/rumble_api.txt
Executable file
|
|
@ -0,0 +1,98 @@
|
|||
|
||||
To automate the process of uploading 100 videos to Rumble and dynamically assigning names and tags, you can use a combination of Python and Selenium for web automation. Here's a high-level overview of how you can achieve this:
|
||||
|
||||
Install Required Libraries:
|
||||
Selenium for browser automation.
|
||||
pandas for handling video data like names and tags.
|
||||
ChromeDriver or any other WebDriver that is compatible with your browser.
|
||||
|
||||
Prepare Your Data:
|
||||
Create a CSV file or a list containing the paths to your videos along with their corresponding names and tags.
|
||||
|
||||
Write the Automation Script:
|
||||
Use Selenium to open the Rumble website, log in, and navigate to the video upload section.
|
||||
Loop through your list of videos, uploading each one and filling out the necessary details.
|
||||
|
||||
Example Script
|
||||
|
||||
Here is a simplified example using Python and Selenium:
|
||||
|
||||
python
|
||||
|
||||
import time
|
||||
import pandas as pd
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
||||
# Load your video data
|
||||
data = pd.read_csv('video_data.csv') # Ensure your CSV has columns: 'path', 'title', 'tags'
|
||||
|
||||
# Setup Selenium WebDriver
|
||||
driver = webdriver.Chrome() # Make sure you have ChromeDriver installed and in your PATH
|
||||
driver.get("https://rumble.com")
|
||||
|
||||
# Log in to Rumble
|
||||
username = "your_username"
|
||||
password = "your_password"
|
||||
|
||||
login_button = driver.find_element(By.LINK_TEXT, "Login")
|
||||
login_button.click()
|
||||
|
||||
username_field = WebDriverWait(driver, 10).until(
|
||||
EC.presence_of_element_located((By.ID, "username_field"))
|
||||
)
|
||||
username_field.send_keys(username)
|
||||
|
||||
password_field = driver.find_element(By.ID, "password_field")
|
||||
password_field.send_keys(password)
|
||||
password_field.send_keys(Keys.RETURN)
|
||||
|
||||
# Wait for login to complete
|
||||
WebDriverWait(driver, 10).until(
|
||||
EC.presence_of_element_located((By.LINK_TEXT, "Upload"))
|
||||
)
|
||||
|
||||
# Loop through videos and upload
|
||||
for index, row in data.iterrows():
|
||||
driver.get("https://rumble.com/upload")
|
||||
|
||||
# Wait for the upload page to load
|
||||
WebDriverWait(driver, 10).until(
|
||||
EC.presence_of_element_located((By.ID, "upload_field"))
|
||||
)
|
||||
|
||||
# Upload video
|
||||
upload_field = driver.find_element(By.ID, "upload_field")
|
||||
upload_field.send_keys(row['path'])
|
||||
|
||||
# Enter title
|
||||
title_field = driver.find_element(By.ID, "title_field")
|
||||
title_field.send_keys(row['title'])
|
||||
|
||||
# Enter tags
|
||||
tags_field = driver.find_element(By.ID, "tags_field")
|
||||
tags_field.send_keys(row['tags'])
|
||||
|
||||
# Submit the form
|
||||
submit_button = driver.find_element(By.ID, "submit_button")
|
||||
submit_button.click()
|
||||
|
||||
# Wait for the upload to complete before proceeding
|
||||
time.sleep(60) # Adjust sleep time based on average upload duration
|
||||
|
||||
driver.quit()
|
||||
|
||||
Additional Considerations
|
||||
|
||||
Handling CAPTCHA: Automating the login process might involve dealing with CAPTCHA, which can be tricky. You may need to solve it manually or use services that solve CAPTCHA.
|
||||
|
||||
Error Handling: Implement error handling to manage scenarios where the upload fails or the page doesn't load as expected.
|
||||
|
||||
Throttling: Be mindful of any upload rate limits Rumble might have. You may need to introduce delays between uploads.
|
||||
|
||||
Browser Headless Mode: For a more seamless experience, consider running the browser in headless mode, especially if you plan to run this script on a server.
|
||||
|
||||
Before running the script, ensure you comply with Rumble's terms of service and automation policies.
|
||||
BIN
_resources/sass 1.pdf
Normal file
BIN
_resources/sass.pdf
Normal file
BIN
_resources/scrcpy-master.zip
Normal file
BIN
_resources/sdras.night-owl-2.0.1.7z
Normal file
67
_resources/setup.md
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
install with in ubuntu
|
||||
`apt install nano micro nginx certbot python3-certbot-nginx btop tmux
|
||||
openjdk-21-jre-headless:amd64 nodejs`
|
||||
|
||||
for minimum npm install do this
|
||||
`apt install npm --no-install-recommends`
|
||||
|
||||
also install pm2
|
||||
`npm install pm2@latest -g`
|
||||
|
||||
before doing this so `apt update` for indexing
|
||||
|
||||
some other through executables
|
||||
broot, dua
|
||||
|
||||
when extracting tar.gz use this
|
||||
`tar -xzvf filename.tar.gz` and when only .tar then use `-xvf` and dont use `z`.
|
||||
|
||||
or for destination
|
||||
`tar -xzvf example.tar.gz -C /path/to/destination/`
|
||||
|
||||
to copy everything including root files do this
|
||||
`cp -r /source/directory/* /destination/directory/` : this will copy regular files
|
||||
`cp -r /source/directory/.* /destination/directory/` : this will copy dotfiles
|
||||
|
||||
|
||||
projects
|
||||
|
||||
1. quiz management site : spring project
|
||||
```sh
|
||||
cd ~/projects/java/quiz_app
|
||||
java -jar demo-0.0.1-SNAPSHOT.jar
|
||||
```
|
||||
2. dropzone
|
||||
```sh
|
||||
cd ~/projects/node/hostfile_project/main
|
||||
pm2 start ecosystem.config.js --no-daemon
|
||||
|
||||
```
|
||||
3. movie recommendation site
|
||||
```sh
|
||||
cd ~/projects/node/movie_back
|
||||
npm start
|
||||
```
|
||||
|
||||
4. smart-brain
|
||||
```sh
|
||||
cd ~/projects/node/face-extractor/smart-brain
|
||||
npm start
|
||||
```
|
||||
|
||||
5. unofficial blog
|
||||
```sh
|
||||
cd ~/projects/static/unofficial_blog_build
|
||||
python3 -m http.server 9020
|
||||
```
|
||||
|
||||
after this expose port 80 and 443 so these sites can be access to main host
|
||||
`podman run -itd -p 80:80 -p 443:443 --name vps1 vps-image:v1 /bin/bash`
|
||||
and
|
||||
`podman exec -it vps1 bash`
|
||||
|
||||
start/reload nginx inside by
|
||||
`nginx -s reload`
|
||||
and
|
||||
to stop and rm container name
|
||||
`podman stop vps1 && podman rm vps1`
|
||||
87
_resources/sha types.txt
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
Other Popular Hash Algorithms:
|
||||
|
||||
SHA-2 Family:
|
||||
The sha1sum tool, which uses SHA-1, is part of the broader SHA (Secure Hash Algorithm) family. Other members of this family include:
|
||||
sha256sum (256-bit hash, more secure than SHA-1)
|
||||
sha224sum (224-bit hash)
|
||||
sha384sum (384-bit hash)
|
||||
sha512sum (512-bit hash, offers maximum security in the SHA family)
|
||||
|
||||
To generate these hashes, tools like sha256sum and sha512sum are typically pre-installed in Linux systems.
|
||||
|
||||
Example:
|
||||
|
||||
sha256sum file.txt
|
||||
sha512sum file.txt
|
||||
|
||||
Blake2:
|
||||
|
||||
Blake2 is a cryptographic hash function designed for high performance and security.
|
||||
There are variations like b2sum for computing Blake2 hashes.
|
||||
Example command:
|
||||
|
||||
b2sum file.txt
|
||||
|
||||
SHA-3 (Keccak):
|
||||
|
||||
SHA-3 is the latest in the SHA family (different underlying algorithm than SHA-2). It includes hashes like:
|
||||
SHA3-224, SHA3-256, SHA3-384, and SHA3-512.
|
||||
Tools like OpenSSL or sha3sum (may require installation) can compute these hashes.
|
||||
Example (using OpenSSL):
|
||||
|
||||
openssl sha3-256 file.txt
|
||||
|
||||
xxHash:
|
||||
|
||||
A non-cryptographic, fast hash function primarily used for checksums and has very high speed.
|
||||
Example (requires installation of xxhash):
|
||||
|
||||
xxhsum file.txt
|
||||
|
||||
CRC32:
|
||||
|
||||
A non-cryptographic checksum often used for simple file integrity checks.
|
||||
Example (using cksum):
|
||||
|
||||
cksum file.txt
|
||||
|
||||
Note: This is not a cryptographic hash.
|
||||
|
||||
Whirlpool:
|
||||
|
||||
Whirlpool is another hashing algorithm, often supported by tools like OpenSSL.
|
||||
Example (using openssl):
|
||||
|
||||
openssl whirlpool file.txt
|
||||
|
||||
RIPEMD Family:
|
||||
|
||||
RIPEMD-128 and RIPEMD-160 are older cryptographic hashes. Less common today but still available through libraries like OpenSSL.
|
||||
Example:
|
||||
|
||||
openssl rmd160 file.txt
|
||||
|
||||
Advanced and Alternative Hashes:
|
||||
|
||||
Tiger: Another hashing algorithm, less common now. Supported by some advanced libraries.
|
||||
Example:
|
||||
|
||||
openssl tiger file.txt
|
||||
|
||||
Adler-32: A checksum algorithm faster than CRC32, used where speed is more important than thorough error detection.
|
||||
Example (using zlib or special tools).
|
||||
|
||||
Checking Available Hash Commands:
|
||||
|
||||
On most Linux systems, you can list the installed checksum/hash commands using:
|
||||
|
||||
compgen -c | grep sum
|
||||
|
||||
This will show different tools like md5sum, sha256sum, b2sum, etc.
|
||||
Comparing with OpenSSL:
|
||||
|
||||
Many of the above hash algorithms can also be computed using openssl. For example:
|
||||
|
||||
openssl dgst -sha256 file.txt
|
||||
openssl dgst -md5 file.txt
|
||||
openssl dgst -sha512 file.txt
|
||||
BIN
_resources/simplescreenrecorder-0.4.4-2-x86_64.pkg.tar.zst
Normal file
BIN
_resources/single_file-1.21.62.rar
Normal file
BIN
_resources/slim-react-starter-main.zip
Normal file
BIN
_resources/socket_def.jpeg
Normal file
|
After Width: | Height: | Size: 135 KiB |
BIN
_resources/source-highlight-3.1.9-11-x86_64.pkg.tar.zst
Normal file
BIN
_resources/source-highlight-3.1.9-11-x86_64.pkg.tar.zst.sig
Normal file
BIN
_resources/spring web demo.zip
Normal file
BIN
_resources/spytify_wine_error.jpeg
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
_resources/sql 1.pdf
Normal file
BIN
_resources/sql.pdf
Normal file
BIN
_resources/sshpass_1.10-0.1_amd64.deb
Normal file
BIN
_resources/stacer-1.1.0-1-x86_64.pkg.tar.zst
Normal file
BIN
_resources/stacer_1.1.0ds-1_amd64.deb
Normal file
BIN
_resources/strawberry-qt5-1.0.20-1-x86_64.pkg.tar.zst
Normal file
70
_resources/tabsAtTtop.html
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
<div class="inline-flex items-center rounded-md shadow-sm">
|
||||
<button
|
||||
class="text-slate-800 hover:text-blue-600 text-sm bg-white hover:bg-slate-100 border border-slate-200 rounded-l-lg font-medium px-4 py-2 inline-flex space-x-1 items-center"
|
||||
>
|
||||
<span
|
||||
><svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-6 h-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M16.862 4.487l1.687-1.688a1.875 1.875 0 112.652 2.652L10.582 16.07a4.5 4.5 0 01-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 011.13-1.897l8.932-8.931zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0115.75 21H5.25A2.25 2.25 0 013 18.75V8.25A2.25 2.25 0 015.25 6H10"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="hidden md:inline-block">Edit</span>
|
||||
</button>
|
||||
<button
|
||||
class="text-slate-800 hover:text-blue-600 text-sm bg-white hover:bg-slate-100 border-y border-slate-200 font-medium px-4 py-2 inline-flex space-x-1 items-center"
|
||||
>
|
||||
<span>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-6 h-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z"
|
||||
/>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="hidden md:inline-block">View</span>
|
||||
</button>
|
||||
<button
|
||||
class="text-slate-800 hover:text-blue-600 text-sm bg-white hover:bg-slate-100 border border-slate-200 rounded-r-lg font-medium px-4 py-2 inline-flex space-x-1 items-center"
|
||||
>
|
||||
<span>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-6 h-6"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="M14.74 9l-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 01-2.244 2.077H8.084a2.25 2.25 0 01-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 00-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 013.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 00-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 00-7.5 0"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="hidden md:inline-block">Delete</span>
|
||||
</button>
|
||||
</div>
|
||||
BIN
_resources/ubuntu_install_erase_decision.jpg
Normal file
|
After Width: | Height: | Size: 647 KiB |
BIN
_resources/unexpected_error_prompt.jpg
Normal file
|
After Width: | Height: | Size: 529 KiB |
BIN
_resources/web_dev_basics.pdf
Normal file
BIN
_resources/wine_common_error.jpeg
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
_resources/xdm-browser-monitor-master-1.zip
Normal file
BIN
_resources/xdm-browser-monitor-master.zip
Normal file
61
joplin notion extension/Web Development/API/Extras.md
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
Extras
|
||||
|
||||
1.
|
||||
2. - https://www.kvstore.io : key-value service 100 keys, 1kb/key.
|
||||
- https://internxt.com/ : e2e file storage from 2gb to 10gb
|
||||
- https://uploadcare.com : image hosting
|
||||
- https://developer.box.com/ : box.com api
|
||||
- https://blackvid.space/#api : api to display movies maybe
|
||||
- sentry2 : markdown previewer paste with sharable links
|
||||
- https://api.invidious.io/ : for invidious
|
||||
- https://martinheinz.dev/blog/113 : curl usage examples
|
||||
- https://github.com/LuanRT/BgUtils : utils to pass botguard and youtube attestation challenges
|
||||
- https://rclone.js.org/ : using rclone with nodejs
|
||||
- https://transfer.adminforge.de/
|
||||
`curl --upload-file ./hello.txt https://transfer.adminforge.de/hello.txt`
|
||||
using https://github.com/dutchcoders/transfer.sh
|
||||
|
||||
|
||||
using jsdom to parse js data
|
||||
```js
|
||||
const fetch=require('node-fetch');
|
||||
// import { JSDom } from "jsdom"
|
||||
const {JSDOM} = require("jsdom")
|
||||
|
||||
const url = 'https://www.mediafire.com/cdn-cgi/challenge-platform/scripts/jsd/main.js';
|
||||
const options = {method: 'GET'};
|
||||
|
||||
|
||||
async function main(){
|
||||
|
||||
try {
|
||||
const response = await fetch(url, options);
|
||||
const data = await response.text();
|
||||
// console.log(data);
|
||||
|
||||
|
||||
|
||||
const dom = new JSDOM()
|
||||
|
||||
global.window = dom.window
|
||||
global.document = dom.window.document
|
||||
|
||||
eval(data)
|
||||
|
||||
console.log(global.window)
|
||||
|
||||
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
```
|
||||
|
||||
|
||||
Others
|
||||
1. 0x0.st
|
||||
`curl -F'file=@yourfile.png' https://0x0.st`
|
||||
2. https://docs.filen.io/docs/api/specs/ : filen, 3 month temp storage
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
Reverse Engineering
|
||||
|
||||
- sdrive(Works only in nodejs due to CORS)
|
||||
|
||||
```jsx
|
||||
const fetch=require('node-fetch')
|
||||
const fs=require('fs')
|
||||
const FormData = require('form-data');
|
||||
const axios=require('axios')
|
||||
|
||||
const file=fs.readFileSync('image_icon.png')
|
||||
|
||||
const url='https://sdrive.app/publicapi/upload'
|
||||
|
||||
// const formData=new FormData()
|
||||
|
||||
// formData.append('file',file)
|
||||
|
||||
|
||||
// fetch(url,{
|
||||
// method: 'post',
|
||||
// body: file
|
||||
|
||||
// })
|
||||
// .then(res=>res.text())
|
||||
// .then(html=>{
|
||||
// fs.writeFileSync('content.html',html)
|
||||
// })
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', file, { filename: 'image_icon.png' }); // Specify the filename when appending the file
|
||||
|
||||
axios.post(url, formData, {
|
||||
headers: {
|
||||
...formData.getHeaders() // Include headers from FormData
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
console.log('File uploaded successfully:', response.data);
|
||||
// Handle the response data as needed
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
// Handle any errors that occurred during the upload
|
||||
});
|
||||
```
|
||||
9
joplin notion extension/Web Development/API/Rumble.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
Rumble
|
||||
https://chatgpt.com/share/6853efa4-c3c9-4089-937e-f3ec1b02b4ab
|
||||
[rumble_api.txt](../../../_resources/rumble_api.txt)
|
||||
|
||||
|
||||
- To get access token
|
||||
https://stackoverflow.com/questions/78031116/how-to-get-access-token-for-rumble-api
|
||||
|
||||
when uploading
|
||||
76
joplin notion extension/Web Development/API/blackbaze.md
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
blackbaze
|
||||
https://www.backblaze.com/docs/cloud-storage-api-operations
|
||||
|
||||
**Note** : sharable link not available without adding credit card
|
||||
|
||||
### for downloading
|
||||
Blackblaze B2 operates with a different API than AWS S3, but downloading a file using a read access token is straightforward. To access files in a B2 bucket, you'll typically follow these steps for authorization and then proceed with downloading the desired file.
|
||||
Steps to Download a File from Backblaze B2
|
||||
|
||||
|
||||
Get Authorization Token: You'll need to authenticate against the B2 API to obtain an authorization token. This is generally done via an API call using your account's Application Key ID and Application Key.
|
||||
|
||||
Make a Download Request: Use the authorization token to make a request to download the file from the bucket.
|
||||
|
||||
Here are detailed steps:
|
||||
Step 1: Get Authorization Token
|
||||
|
||||
Use the following endpoint to get your authorization token:
|
||||
|
||||
Request:
|
||||
```bash
|
||||
curl -X GET "https://api.backblazeb2.com/b2_authorize_account" \
|
||||
-H "Authorization: Basic $(echo -n 'APPLICATION_KEY_ID:APPLICATION_KEY' | base64)"
|
||||
```
|
||||
Replace `APPLICATION_KEY_ID` and `APPLICATION_KEY` with your actual credentials.
|
||||
|
||||
Response:
|
||||
|
||||
This will return a JSON object containing your apiUrl, authorizationToken, and other details:
|
||||
|
||||
```json
|
||||
{
|
||||
"accountId": "some_account_id",
|
||||
"bucketId": "some_bucket_id",
|
||||
"bucketName": "your_bucket",
|
||||
"downloadUrl": "https://f002.backblazeb2.com",
|
||||
"authorizationToken": "your_authorization_token",
|
||||
...
|
||||
}
|
||||
```
|
||||
Step 2: Download the File
|
||||
|
||||
Once you have the downloadUrl and authorizationToken, you can download files stored in your B2 bucket. You'll need to format the URL correctly based on the file's path in the bucket.
|
||||
|
||||
Example cURL Command to Download File:
|
||||
|
||||
Assuming your download URL is https://f002.backblazeb2.com and you have the bucket name and file name:
|
||||
|
||||
`curl -L -o LOCAL_FILENAME "https://f002.backblazeb2.com/file/Bucket_Name/Path/To/Your/File.txt" \
|
||||
-H "Authorization: your_authorization_token"`
|
||||
|
||||
Example of the Full Process
|
||||
|
||||
Here’s a combined example of both steps in shell commands:
|
||||
```bash
|
||||
# Step 1: Get Authorization Token
|
||||
auth_response=$(curl -s -X GET "https://api.backblazeb2.com/b2_authorize_account" \
|
||||
-H "Authorization: Basic $(echo -n 'APPLICATION_KEY_ID:APPLICATION_KEY' | base64)")
|
||||
|
||||
# Extract the necessary fields using jq (install it if you don't have it)
|
||||
apiUrl=$(echo $auth_response | jq -r '.apiUrl')
|
||||
downloadUrl=$(echo $auth_response | jq -r '.downloadUrl')
|
||||
authToken=$(echo $auth_response | jq -r '.authorizationToken')
|
||||
|
||||
# Step 2: Download the file
|
||||
curl -L -o LOCAL_FILENAME "${downloadUrl}/file/YOUR_BUCKET_NAME/PATH/TO/YOUR/FILE.txt" \
|
||||
-H "Authorization: ${authToken}"
|
||||
```
|
||||
|
||||
Important Notes
|
||||
|
||||
Authorization: Make sure to replace APPLICATION_KEY_ID, APPLICATION_KEY, Your_Bucket_Name, and PATH/TO/YOUR/FILE.txt with your actual values.
|
||||
Token Validity: The authorization token will expire after a limited time, so you may need to call the authorization endpoint to get a new token if it has expired.
|
||||
Using Environment Variables: For security, consider storing sensitive credentials in environment variables instead of hardcoding them directly into your scripts.
|
||||
|
||||
With these steps, you should be able to easily download files from Backblaze B2 using your read access token!
|
||||
31
joplin notion extension/Web Development/API/catbox.md
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
catbox
|
||||
|
||||
- https://catbox.moe/tools.php
|
||||
- cURL to API
|
||||
If you want to make curl requests to the API, here are examples of both.
|
||||
`curl -F "reqtype=urlupload" -F "userhash=####" -F "url=https://files.catbox.moe/174bac.jpg" https://catbox.moe/user/api.php`
|
||||
|
||||
` curl -F "reqtype=fileupload" -F "userhash=####" -F "fileToUpload=@cutie.png" https://catbox.moe/user/api.php `
|
||||
|
||||
|
||||
Converting to axios
|
||||
```js
|
||||
import axios from 'axios';
|
||||
import FormData from 'form-data';
|
||||
import * as fs from 'fs';
|
||||
|
||||
const form = new FormData();
|
||||
form.append('reqtype', 'fileupload');
|
||||
form.append('userhash', '####');
|
||||
form.append('fileToUpload', fs.readFileSync('cutie.png'), 'cutie.png');
|
||||
|
||||
const response = await axios.post(
|
||||
'https://catbox.moe/user/api.php',
|
||||
form,
|
||||
{
|
||||
headers: {
|
||||
...form.getHeaders()
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
43
joplin notion extension/Web Development/API/cloudinary.md
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
cloudinary
|
||||
https://cloudinary.com/documentation/upload_images
|
||||
`https://api.cloudinary.com/v1_1/<cloud name>/<resource_type>/upload`
|
||||
`cloud name` is the name of your Cloudinary product environment.
|
||||
`resource_type` is the type of file to upload. Valid values: image, raw, video and auto to automatically detect the file type.
|
||||
|
||||
for upload
|
||||
```bash
|
||||
curl --request POST \
|
||||
--url https://api.cloudinary.com/v1_1/cld-docs/auto/upload \
|
||||
--header 'content-type: multipart/form-data' \
|
||||
--form file=@path/to/file/sample.zip \
|
||||
--form api_key=<API_KEY> \
|
||||
--form upload_preset=ml_default
|
||||
```
|
||||
|
||||
response body
|
||||
```json
|
||||
{
|
||||
"asset_id": "3515c6000a548515f1134043f9785c2f",
|
||||
"public_id": "gotjephlnz2jgiu20zni",
|
||||
"version": 1719307544,
|
||||
"version_id": "7d2cc533bee9ff39f7da7414b61fce7e",
|
||||
"signature": "d0b1009e3271a942836c25756ce3e04d205bf754",
|
||||
"width": 1920,
|
||||
"height": 1441,
|
||||
"format": "jpg",
|
||||
"resource_type": "image",
|
||||
"created_at": "2024-06-25T09:25:44Z",
|
||||
"tags": [],
|
||||
"pages": 1,
|
||||
"bytes": 896838,
|
||||
"type": "upload",
|
||||
"etag": "2a2df1d2d2c3b675521e866599273083",
|
||||
"placeholder": false,
|
||||
"url": "http://res.cloudinary.com/cld-docs/image/upload/v1719307544/gotjephlnz2jgiu20zni.jpg",
|
||||
"secure_url": "https://res.cloudinary.com/cld-docs/image/upload/v1719307544/gotjephlnz2jgiu20zni.jpg",
|
||||
"asset_folder": "",
|
||||
"display_name": "gotjephlnz2jgiu20zni",
|
||||
"original_filename": "sample",
|
||||
"api_key": "614335564976464"
|
||||
}
|
||||
```
|
||||
36
joplin notion extension/Web Development/API/fileditch.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
fileditch
|
||||
https://fileditch.com
|
||||
|
||||
- To upload
|
||||
To upload using curl or make a tool you can post using:
|
||||
`curl -i -F files[]=@yourfile.jpeg https://up1.fileditch.com/upload.php` (JSON Response)
|
||||
|
||||
Javascript(Browser)
|
||||
|
||||
```js
|
||||
const fileInput = document.getElementById('fileInput');
|
||||
|
||||
fileInput.addEventListener('change', async (event) => {
|
||||
const file = fileInput.files[0];
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('files[]', file);
|
||||
|
||||
fetch('https://up1.fileditch.com/upload.php', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
})
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
return response.text();
|
||||
})
|
||||
.then((data) => {
|
||||
console.log('Upload successful:', data);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error during upload:', error);
|
||||
});
|
||||
})
|
||||
```
|
||||
61
joplin notion extension/Web Development/API/genius.md
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
genius
|
||||
|
||||
|
||||
```js
|
||||
|
||||
const {parse}=require('node-html-parser')
|
||||
const fetch= require('node-fetch')
|
||||
|
||||
async function fetchLyricsFromLink(lyricUrl){
|
||||
const lyricContainerSelector= 'div[data-lyrics-container="true"]'
|
||||
|
||||
// const htmlString= fs.readFileSync('lyrics.html')
|
||||
|
||||
|
||||
const res= await fetch('https://genius.com/Green-day-the-american-dream-is-killing-me-lyrics')
|
||||
const htmlString= await res.text();
|
||||
|
||||
// const htmlString= `<div>
|
||||
// <div id="lis">
|
||||
// <ul>
|
||||
// <li>first</li>
|
||||
// <li>second</li>
|
||||
// </ul>
|
||||
// </div>
|
||||
// </div>`
|
||||
|
||||
const root = parse(htmlString)
|
||||
|
||||
// const obj=root.querySelector(lyricContainerSelector)
|
||||
const arr=root.querySelectorAll(lyricContainerSelector)
|
||||
|
||||
|
||||
// console.log(obj.outerHTML)
|
||||
|
||||
let str=""
|
||||
|
||||
for(let element of arr){
|
||||
// statements
|
||||
str+=element.textContent
|
||||
str+='\n'
|
||||
|
||||
}
|
||||
|
||||
return str;
|
||||
|
||||
// fs.writeFileSync('parsed_lyrics.html',str)
|
||||
|
||||
|
||||
}
|
||||
|
||||
fetch('https://genius.com/api/search/multi?per_page=5&q=Faith --Weeknd')
|
||||
.then(res=>res.json())
|
||||
.then(async(data)=>{
|
||||
const url= data.response.sections[0].hits[0].result.url
|
||||
console.log('url: ',url)
|
||||
const lyrics= await fetchLyricsFromLink(url)
|
||||
console.log('lyrics: ',lyrics)
|
||||
})
|
||||
.catch(console.log)
|
||||
|
||||
```
|
||||
14
joplin notion extension/Web Development/API/mediafire.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
mediafire
|
||||
|
||||
- https://www.mediafire.com/developers/ : not anymore
|
||||
|
||||
|
||||
## Steps
|
||||
1. Get a session token. Note : Session token will be expired after a couple period of time so is cookie so need to generate them again, means somehow automate login.
|
||||
2. Using it to get folders and files info of root directory
|
||||
for folder and files content 2 api api is called and eveyrthing is same in request body except content-type
|
||||
request body is of form-data, files one will give the sharable link too
|
||||
folderkey field contains key of parent folder, root one is basically 'myfiles'.
|
||||
3. for uploadfile, it will check the folder where it is uploaded and quickkey of folder will be there too in response, then it will upload as `application/octlet-stream`, and will send filehash too in headers which is of `sha256sum`. After the resulable upload api, key will be get which will be used for next poll upload thing
|
||||
|
||||
4. for getting sharable link : : "https://www.mediafire.com/file/7mpw92w27etlaex/Restfox-main.zip/file" . so format is `https://www.mediafire.com/file/<quick_key>/<filename>/file` or just until quick_key is enough too
|
||||
39
joplin notion extension/Web Development/API/nextcloud.md
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
nextcloud
|
||||
|
||||
upload file
|
||||
https://docs.nextcloud.com/server/latest/developer_manual/client_apis/WebDAV/basic.html#uploading-files
|
||||
```bash
|
||||
curl -u username:password \
|
||||
--request PUT \
|
||||
--url https://nextcloud-fi.webo.hosting/remote.php/dav/files/<user_name>/alternative-front-ends-main.zip \
|
||||
--header 'content-type: application/octet-stream' \
|
||||
--data-binary @path/to/your/local/file
|
||||
```
|
||||
|
||||
|
||||
generating sharable link
|
||||
https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-share-api.html
|
||||
|
||||
- auth
|
||||
`curl -u username:password -X GET 'https://cloud.example.com/ocs/v1.php/...' -H "OCS-APIRequest: true"`
|
||||
|
||||
- get shareable items list
|
||||
`curl -u username:password -X GET 'https://cloud.example.com/ocs/v1.php/shares' -H "OCS-APIRequest: true"`
|
||||
- create sharable link
|
||||
```bash
|
||||
curl -u username:password --request POST \
|
||||
--url https://nextcloud-fi.webo.hosting/ocs/v2.php/apps/files_sharing/api/v1/shares \
|
||||
--header 'content-type: application/x-www-form-urlencoded' \
|
||||
--header 'ocs-apirequest: true' \
|
||||
--data path=/Photos/Birdie.jpg \
|
||||
--data shareType=3
|
||||
```
|
||||
|
||||
for nodejs fetch, -u username:password needs to be converted into basic auth header so convert `username:password` string to base64 and pass it header as `authorization: Basic <base64_version>`
|
||||
- upload file
|
||||
```bash
|
||||
curl -u username:password --request PUT \
|
||||
--url https://nextcloud-fi.webo.hosting/remote.php/dav/files/<username>/alternative-front-ends-main.zip \
|
||||
--header 'content-type: application/octet-stream' \
|
||||
--data-binary @path/to/your/local/file.zip
|
||||
```
|
||||
5
joplin notion extension/Web Development/API/pastebin.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
pastebin
|
||||
|
||||
- With curl
|
||||
`curl -X POST -d 'api_dev_key=YOUR API DEVELOPER KEY' -d 'api_paste_code=test' -d 'api_option=paste' "https://pastebin.com/api/api_post.php"`
|
||||
|
||||
58
joplin notion extension/Web Development/API/sdrive.md
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
sdrive(do not work in client side)
|
||||
|
||||
```jsx
|
||||
import axios from "axios";
|
||||
import FormData from "form-data";
|
||||
import fs from "fs";
|
||||
import dotenv from "dotenv";
|
||||
import mime from "mime-types";
|
||||
import path from "path";
|
||||
dotenv.config();
|
||||
async function uploadFile(fileStream, filename) {
|
||||
let formData = new FormData();
|
||||
let apikey = process.env.apikey;
|
||||
let base_url = process.env.base_url || "https://v3.sdrive.app";
|
||||
if (!apikey) {
|
||||
console.log("Please add your credentials to the .env file");
|
||||
process.exit();
|
||||
}
|
||||
|
||||
let mimetype = mime.lookup(path.extname(filename));
|
||||
formData.append("fileupload", fileStream, {
|
||||
filename: filename,
|
||||
contentType: mimetype,
|
||||
});
|
||||
formData.append("apikey", apikey);
|
||||
formData.append("network", "shdwdrive");
|
||||
|
||||
return await axios
|
||||
.post(base_url + "/upload", formData, {
|
||||
headers: formData.getHeaders(), // Set headers from formData
|
||||
})
|
||||
.catch((error) => {
|
||||
const errorInfo = {
|
||||
status: error.response.status,
|
||||
statusText: error.response.statusText,
|
||||
data: error.response.data,
|
||||
};
|
||||
throw Error(JSON.stringify(errorInfo));
|
||||
})
|
||||
.then((response) => {
|
||||
return response.data;
|
||||
});
|
||||
}
|
||||
|
||||
// Example usage
|
||||
(async () => {
|
||||
const inputPath = process.argv[2];
|
||||
const filename = inputPath.split("/").pop();
|
||||
const fileStream = fs.createReadStream(inputPath);
|
||||
try {
|
||||
const response = await uploadFile(fileStream, inputPath);
|
||||
console.log(response);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
})();
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
sentry2 (stellar)
|
||||
|
||||
```js
|
||||
const fetch=require('node-fetch')
|
||||
|
||||
// const baseurl='https://rentry.co'
|
||||
const baseurl='https://sentrytwo.com'
|
||||
|
||||
const fetchurl=`${baseurl}/api/new`
|
||||
|
||||
const jsbody={
|
||||
content : 'this is text',
|
||||
custom_url : '',
|
||||
edit_password: 'secret',
|
||||
|
||||
}
|
||||
|
||||
const requestBody = new URLSearchParams(jsbody);
|
||||
|
||||
const csrfToken='R1ukF9nRyNITFeftszagNiM5g2izx0UtfNkPOIwurFqtVP63L00pQh1ahD6dmfj5' // for rentry, epire in 2025
|
||||
|
||||
fetch(fetchurl,{
|
||||
method : 'POST',
|
||||
headers: {
|
||||
// 'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Content-Type': 'application/json',
|
||||
// "Referer": 'https://rentry.co',
|
||||
// 'X-CSRF-Token': csrfToken,
|
||||
},
|
||||
body : JSON.stringify(jsbody)
|
||||
})
|
||||
.then(res=>res.text())
|
||||
.then(data=>{
|
||||
console.log('data: ',data)
|
||||
})
|
||||
.catch(err=>{
|
||||
console.log('err: ',err)
|
||||
})
|
||||
|
||||
```
|
||||
127
joplin notion extension/Web Development/API/sirv.md
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
sirv(500 mb storage)
|
||||
|
||||
- https://apidocs.sirv.com
|
||||
|
||||
nodejs
|
||||
```jsx
|
||||
const http = require("https");
|
||||
|
||||
|
||||
|
||||
const options = {
|
||||
"method": "POST",
|
||||
"hostname": "api.sirv.com",
|
||||
"port": null,
|
||||
"path": "/v2/token",
|
||||
"headers": {
|
||||
"content-type": "application/json",
|
||||
"authorization": "Bearer BEARER_TOKEN_HERE"
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const req = http.request(options, function (res) {
|
||||
const chunks = [];
|
||||
|
||||
|
||||
res.on("data", function (chunk) {
|
||||
chunks.push(chunk);
|
||||
});
|
||||
|
||||
|
||||
res.on("end", function () {
|
||||
const body = Buffer.concat(chunks);
|
||||
console.log(body.toString());
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
req.write("{\"clientId\":\"ZcnZNfzwRhQExoHFoGpxWJ4p2R\",\"clientSecret\":\"TM3d0CfXxusKMpH3x7kHJYD40qJIR3omTIGXP6wPPkXpIUKLEz/dOJ9v6LbXra3y67XsaGK7iQPmnAuD+fzj+Q==\"}");
|
||||
req.end();
|
||||
|
||||
```
|
||||
|
||||
|
||||
Javascript(Vanilla)
|
||||
```jsx
|
||||
const data = "{\"clientId\":\"ZcnZNfzwRhQExoHFoGpxWJ4p2R\",\"clientSecret\":\"TM3d0CfXxusKMpH3x7kHJYD40qJIR3omTIGXP6wPPkXpIUKLEz/dOJ9v6LbXra3y67XsaGK7iQPmnAuD+fzj+Q==\"}";
|
||||
|
||||
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.withCredentials = true;
|
||||
|
||||
|
||||
xhr.addEventListener("readystatechange", function () {
|
||||
if (this.readyState === this.DONE) {
|
||||
console.log(this.responseText);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
xhr.open("POST", "https://api.sirv.com/v2/token");
|
||||
xhr.setRequestHeader("content-type", "application/json");
|
||||
xhr.setRequestHeader("authorization", "Bearer BEARER_TOKEN_HERE");
|
||||
|
||||
|
||||
xhr.send(data);
|
||||
|
||||
```
|
||||
|
||||
to upload file with curl
|
||||
```bash
|
||||
curl --request POST \
|
||||
--url 'https://api.sirv.com/v2/files/upload?filename=%2FREST%20API%20Examples%2Fuploaded.txt' \
|
||||
--header 'authorization: Bearer BEARER_TOKEN_HERE' \
|
||||
--header 'content-type: application/octet-stream' \
|
||||
--data-binary @path/to/your/local/file.txt
|
||||
```
|
||||
|
||||
with nodejs
|
||||
```js
|
||||
const fetch = require("node-fetch");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const uploadFile = async () => {
|
||||
try {
|
||||
// Replace with your own details
|
||||
const apiURL = "https://api.sirv.com/v2/files/upload?filename=%2FREST%20API%20Examples%2Fuploaded.txt";
|
||||
const token = "BEARER_TOKEN_HERE";
|
||||
const filePath = path.join(__dirname, "your-local-file.txt"); // Path to your local file
|
||||
|
||||
// Read the file as binary data
|
||||
const fileStream = fs.createReadStream(filePath);
|
||||
|
||||
// Make the POST request with binary data
|
||||
const response = await fetch(apiURL, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
"Content-Type": "application/octet-stream", // Appropriate content-type for binary file uploads
|
||||
},
|
||||
body: fileStream, // Use the file stream as the request body
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
console.log("File uploaded successfully:", data);
|
||||
} else {
|
||||
const error = await response.text();
|
||||
console.error("Error uploading file:", error);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error uploading file:", error.message);
|
||||
}
|
||||
};
|
||||
|
||||
// Start the file upload
|
||||
uploadFile();
|
||||
```
|
||||
|
||||
sharable link format
|
||||
https://platletinvt.sirv.com/Images/Apple%20Watch%20white.jpg
|
||||
where this jpg file is in Images folder
|
||||
platletinvt is username
|
||||
Images is folder name
|
||||
rest is filename
|
||||
48
joplin notion extension/Web Development/API/tastedive.md
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
tastedive
|
||||
|
||||
nodejs
|
||||
```js
|
||||
const fetch= require('node-fetch')
|
||||
|
||||
const getSimilarMovies=async(input)=>{
|
||||
|
||||
|
||||
// const input="batman"
|
||||
const searchurl=`https://tastedive.com/api/search?query=${input}&take=9&page=1&searchCategory=default&types=urn:entity:artist,urn:entity:movie,urn:entity:tv_show,urn:entity:book,urn:entity:videogame,urn:entity:podcast,urn:entity:person,urn:entity:place,urn:entity:brand`
|
||||
|
||||
|
||||
try{
|
||||
|
||||
const searchres=await fetch(searchurl)
|
||||
const searchdata= await searchres.json()
|
||||
|
||||
// console.log('data :', searchdata)
|
||||
|
||||
const entityID=searchdata.results?.[0]?.entity_id
|
||||
|
||||
if(entityID){
|
||||
const similarurl= `https://tastedive.com/api/getRecsByCategory?page=1&entityId=${entityID}&category=movies&limit=18`
|
||||
const similarRes = await fetch(similarurl)
|
||||
const similarData= await similarRes.json()
|
||||
|
||||
console.log('similarData: ',similarData)
|
||||
|
||||
return similarData
|
||||
|
||||
|
||||
}
|
||||
else{
|
||||
console.log('no entity_id')
|
||||
}
|
||||
}
|
||||
|
||||
catch(err){
|
||||
|
||||
// console.log('err: ', err)
|
||||
throw new Error(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports={getSimilarMovies}
|
||||
```
|
||||
83
joplin notion extension/Web Development/API/uploadcare.md
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
uploadcare
|
||||
|
||||
javascript(vanilla)
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<input type="file" name="" id=""><br>
|
||||
<button>Upload</button>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.6.7/axios.min.js" integrity="sha512-NQfB/bDaB8kaSXF8E77JjhHG5PM6XVRxvHzkZiwl3ddWCEPBa23T76MuWSwAJdMGJnmQqM0VeY9kFszsrBEFrQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
||||
<script>
|
||||
const url='https://upload.uploadcare.com/base/'
|
||||
const pub_key='b182e75f948ada5a015f'
|
||||
|
||||
|
||||
const fileEle=document.querySelector("input")
|
||||
const button=document.querySelector("button")
|
||||
|
||||
const formdata= new FormData()
|
||||
button.addEventListener("click",()=>{
|
||||
const file=fileEle.files[0];
|
||||
console.log('file: ',file)
|
||||
formdata.append("UPLOADCARE_PUB_KEY",pub_key)
|
||||
// formdata.append("my_file.jpg",file)
|
||||
formdata.append("my_file.jpg",file)
|
||||
|
||||
axios.post(url, formdata, {
|
||||
|
||||
})
|
||||
.then(response => {
|
||||
console.log(response.data);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(error);
|
||||
});
|
||||
|
||||
// fetch(url,{
|
||||
// method: 'POST',
|
||||
// headers: {
|
||||
// "Content-Type": "multipart/form-data"
|
||||
// },
|
||||
// body: formdata,
|
||||
// })
|
||||
// .then(res=>res.json())
|
||||
// .then(data=>{
|
||||
// console.log('data: ',data)
|
||||
|
||||
// })
|
||||
// .catch(err=>{
|
||||
// console.log('err: ',err)
|
||||
// console.log('err message: ',err.message)
|
||||
// })
|
||||
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
or with fetch
|
||||
```js
|
||||
fetch(url,{
|
||||
method: 'POST',
|
||||
|
||||
body: formdata,
|
||||
})
|
||||
.then(res=>res.json())
|
||||
.then(data=>{
|
||||
console.log('data: ',data)
|
||||
|
||||
})
|
||||
.catch(err=>{
|
||||
console.log('err: ',err)
|
||||
console.log('err message: ',err.message)
|
||||
})
|
||||
```
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
Fragmentation
|
||||
|
||||
- Answering to your question. Fragmentation occurs because sometimes when you allocate something in memory it doesn't occupy contigous memory cells, to understand it you could imagine a train with wagons. The information that you are putting in this train is getting in the wagons but not in a row, not in a contigous way. Now, since you have to manage memory using partitions you could find yourself with a single process scattered in different memory cells that are being partition edfor that process not leaving enough space for new processes. When you take the old process out of the memory, it doesn't automatically free the space it occupied (in some systems) and this causes fragmentation and memory leaks.
|
||||

|
||||
103
joplin notion extension/Web Development/Basics/Set 1.md
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
Set 1
|
||||
|
||||
- Internet of Things
|
||||
The Internet of Things (IoT) describes the network of physical objects—“things”—that are embedded with sensors, software, and other technologies for the purpose of connecting and exchanging data with other devices and systems over the internet. Like smartwathes, sensors in machines, etc
|
||||
- Domain names
|
||||
gmail.com is domain name. org, .com are domain name extension or top level domain
|
||||
- http vs tcp
|
||||
TCP is the raw data transfer protocol, and http is the encoding sort of TCP manages the data stream, whereas HTTP describes what the data in the stream contains.
|
||||
So HTTP runs on top on TCP
|
||||
also
|
||||
IP indicates, among other information, which IP address a packet should go to (think of a mailing address), while TCP indicates which port a packet should go to at each IP address (think of the floor of a building or an apartment number).so ip address is IP and its port part is tcp.
|
||||
- Linux kernel
|
||||
https://www.youtube.com/watch?v=mycVSMyShk8
|
||||

|
||||
- IPv4 address
|
||||
https://www.digitalocean.com/community/tutorials/understanding-ip-addresses-subnets-and-cidr-notation-for-networking
|
||||
It is 32 bit address contains 4 octlets as each section os if 8 bits/1 byte.
|
||||
from 0.0.0.0 to 255.255.255.255 . so total nodes are 2^32
|
||||
eg
|
||||
`192.168.0.5`
|
||||
- IPv6 address
|
||||
It is 128 bit address that contains 8 segments of 4 hex digits
|
||||
`1203:8fe0:fe80:b897:8990:8a7c:99bf:323d`
|
||||
Compact version is allowed too means we can remove leading zeroes (0s from left)
|
||||
`8703:0087:0874:0000:76b1....`
|
||||
it can be written as
|
||||
`8703:87:874::76b1....`
|
||||
Compacting rule is that it can be decompressed back too. So this leading we r removing whole segment bcz of `0000` to `::` then this can be done only one time bcz
|
||||
`1203:8fe0:0000:b897:8990:0000:0000:323d`
|
||||
If delete whole segment 2 times then
|
||||
`1203:8fe0::b897:8990::323d`
|
||||
now in when decompressing it we dont know which side have how many segments. it can be either
|
||||
`1203:8fe0:0000:b897:8990:0000:0000:323d` (correct one)
|
||||
`1203:8fe0:0000:0000:b897:8990:0000:323d` (wrong one)
|
||||
- 2 types of ipv6 address in router
|
||||
https://www.quora.com/Why-do-I-have-2-different-IPv6-addresses-in-my-device
|
||||
starting with `fe80` whch ends with scope link is for local connection only and never go outside the subnet and other one dont start with `fe80` and send with scope global can be used for all the actual client communications you would expect to see out across the internet etc.
|
||||
- IPv4 Classes
|
||||
|
||||
- Class A : 0.0.0.0 to 127.255.255.255
|
||||
for large networks like ISPs
|
||||
- Class B : 128.0. 0.0 to 191.255. 255.255
|
||||
for medium networks like enterprise networks
|
||||
- Class C : 192.0.1.1 - 223.255.254.254
|
||||
for small networks ie LAN
|
||||
- Class D : 224.0.0.0 - 239.255.255.255
|
||||
for multicast addressing
|
||||
- Class E : 240.0.0.0 - 255.255.255.254
|
||||
for experimental purposes
|
||||
- Reserved IP address
|
||||
localhost ie loopback range is useful reserved address specified from `127.0.0.0` to `127.255.255.255`
|
||||
Each class have their own reserved private address
|
||||
- Class A : 10.0.0.0 to 10.255.255.255
|
||||
- Class B : 172.16.0.0 to 172.31.255.255
|
||||
- Class C : 192.168.0.0 to 192.168.255.255
|
||||
Their advantage is that if there is no internet then computer can use these private IPv4 address
|
||||
- Netmasks and Subnets
|
||||
Netmask is also called subnet mask
|
||||
The process of dividing a network into smaller network sections is called subnetting
|
||||
Each address space is divided into network and host potion. In class C ip `192.168.0.15` first 3 octlets like `192.168.0` is network and `15` is the host
|
||||
Subnetting is the process of dividing a single network into smaller subnetworks, each with its own network address and range of usable internet protocol (IP) addresses.
|
||||
Subnet mask is specification/config which contain how many bits are allocated to network portion. In case of home wifi router subnet is 24 means 3 octelts `192.168.0` and last one ie `15` is host one
|
||||
Subnet /24 means 3 oclets of network portion so it can be represented as `255.255.255.0` 0 represents host section and (255) with base 10/11111111 with base 2 represents network section
|
||||
- Calculating network portion and host portion with subnet
|
||||
Using Bitwise AND.
|
||||
In `255.255.255.0` the first 24 bits are 1 and others r 0 so when operated with `192.168.0.15` then first 3 octlets will be come as of network portion and rest host portion bcz
|
||||
1.1=1
|
||||
1.0=0
|
||||
1.X=X
|
||||
0.X=0
|
||||
0 and 255 host are reserved so they cant be used so that leave us with 254 hosts.
|
||||
|
||||
Note : Wifi router can connect upto 250 devices so a single IP will connect to 250 devices. Other than 0 and 255 4 more r reserved bcz of mesh network maybe
|
||||
for wifi router
|
||||
subnet mask for ipv6 address in wifi router is /64 means first half of network section, rest for host section
|
||||
- Subnetting
|
||||
If we have subnet mask `255.255.255.0` and if we wanna divide our host portion into 2 parts then use the first bit for that thus dividing them into 128 and 128.
|
||||
From
|
||||
`1111 1111 1111 0000-0000`
|
||||
To
|
||||
`1111-1111 1111-1111 1111-1111 1000-0000`
|
||||
So The ipv4 address is `192.168.0.128` used a divider. Now we have 2 subnetworks.
|
||||
First subnetworks from `192.168.0.1` to `192.168.0.127`
|
||||
Second subnetworks from `192.168.0.129` to `192.168.0.255`
|
||||
This happened after using 1 bit of host portion. If used more bits then more subnetting is possible.
|
||||
- CIDR Notation
|
||||
A system called 'Classless Inter-Domain Routing' or CIDR is alternative to traditional subnetting
|
||||
Instead of using traditional subnetting which has a fixed netmask like in router it is `255.255.255.0` we can have our own specification of allocation of network and host section of ip address. We can use this `192.168.0.15/24` (CIDR notation) which means ip address is `192.168.0.15` and 24 bits for network and rest 8 for host.
|
||||
We can change this to `192.168.0.15/23`. Now we can have ineresting IP addresses like range from `192.168.0.0` to `192.168.0.255` and `192.168.1.0` to `192.168.1.255` so total of 512 hosts
|
||||
- Nginx, traefik, istio, linkerd, consul etc are called ingresses and service meshes
|
||||
|
||||
|
||||
- how vpn transports http traffic
|
||||
1. Your browser sends HTTP traffic (which uses TCP).
|
||||
2. The VPN software wraps (encapsulates) that TCP packet.
|
||||
3. The encapsulated packet is sent to the VPN server using UDP.
|
||||
4. The VPN server unwraps it and forwards the original HTTP request to the website.
|
||||
5. The response comes back the same way.
|
||||
|
||||
|
||||
http codes
|
||||
- https://www.dotcom-monitor.com/blog/the-10-most-common-http-status-codes/
|
||||
[90 Common HTTP Status Codes_ Full Reference _ Triage (2_9_2026 5_39_44 pm).u.zip.html](../../../_resources/90%20Common%20HTTP%20Status%20Codes_%20Full%20Reference%20_%20Tria.html)
|
||||
60
joplin notion extension/Web Development/Basics/Theory.md
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
Theory
|
||||
|
||||
1_WHAT IS STORAGE VIRTUALIZATION?
|
||||
|
||||
|
||||
Storage virtualization is the pooling of physical storage from multiple storage devices into what appears to be a single storage device -- or pool of available storage capacity. A central console manages the storage.
|
||||
|
||||
|
||||
2_WHAT REALLY IS STORAGE VIRTUALIZATION?
|
||||
|
||||
storage virtualization is when you take multiple physical storage devices and combine them to make one, or multiple "virtual" storage devices with the storage capacity to meet your needs
|
||||
|
||||
|
||||
|
||||
3_WHAT DOES STORAGE VIRTUALIZATION DO?
|
||||
|
||||
|
||||
so lets say you work IT at a hospital, and you got 500 different computers each with 1TB of hard drive space each, and they are all connected, controlled, and managed by an internal hospital IT network, and your the IT network guy.
|
||||
|
||||
now, all those hard drives are being used, each employee with a computer has their operating system installed, and their own personal work files, which means that each hard drive is going to have a different amount of space left on the hard drive, some might have 900GB of data left, some 500GB, some 200GB, but each and everyone one has a different amount of storage space.
|
||||
|
||||
now lets say, you as the network IT guy, wanted to create a storage space, out of 1GB, of all the hard drives you have access to, so you wanted to go into each employees computer, and borrow 1GB from each computer, and create a storage space out of all those 1GB's, you borrowed, totalling a drive of 500GB,
|
||||
|
||||
with storage virtualization you can do exactly that, you can take separate physical storage devices, you can take all of the storage space they have or only a part, and create a virtual storage device
|
||||
|
||||
|
||||
|
||||
Transpiling
|
||||
It is often called 'transpiling', when you translate code with JS-preprocessors like CoffeeScript, TypeScript (you name it) to plain JavaScript.
|
||||
Whereas compiling and interpreter converts code into machine language
|
||||
|
||||
CI/CD
|
||||
- pull code from git repo, build it and deploy it, these are done by scripts
|
||||
|
||||
|
||||
**Kernal,GNU**
|
||||
- Think of GNU as a set of tools, kind of like Microsoft Office is a set of programs.
|
||||
The design of the Linux filesystem (treating everything as a file or directory) is a choice made for the Kernel, and programs that want to have any chance of running need to adhere to the Kernel
|
||||
- filesystem : So we have a storage device, this could be a HDD or SDD that a computer can write data to.
|
||||
Ontop of that we have firmware that sits on said physical device, this is rarely updated as it's very simple and straightforward
|
||||
Above this we have the driver for the computer. This provides a standardized manner in which the operating system can read and write to the storage device.
|
||||
|
||||
The OS uses partitions to segment out where data can go. The format of data ontop of a partition varies, being something like NTFS, FAT32, ext4, btrfs, APFS, ZFS etc.
|
||||
|
||||
The "filesystem" can refer to one of two things:
|
||||
1. The actual formatting of how the OS reads the partition for data. ext4 and btrfs work by using something called `inodes` that define basic metadata about a file and the start and end of it's payload... So if you lose the inode you basically lose the file
|
||||
2. General interfacing with a formatted partition
|
||||
e.g. interfacing with the filesystem
|
||||
3. metadata is a common term for data providing information about one or more other pieces of data, when inode is a type of metadata that stores basic information about a regular file, directory, or other file system object.
|
||||
4. The kernel is kind of like the nervous system of a human, it does a lot of control and operation of the low-level functionality.
|
||||
The two common Kernel interfaces are as a filesystem (How linux and unix work) of via APIs (Windows 🤢)
|
||||
Any command you enter on a PTY first asks the kernel to start a new task (process) with some given parameters. It locates the executable and creates a new process passing the parameters that were provided. It bill bind an input and output stream (stdin/stderr/stdout) etc and let the program access sockets and whatever else based on permissions defined for the executor of the program and the program itself
|
||||
5. "space" refers to the execution of a program.
|
||||
If something runs in "kernel" space that means it's running under the operating system. If it runs in "user" space that means it runs for a particular user"
|
||||
|
||||
Think of it like this: Nano runs for user `robin` and xorg runs for user `root`
|
||||
The init system controls the root process, and which `user` owns it. I'm not really an expert on this so take my explanation with a grain of salt
|
||||
per a stackoverflow thread, a program run by the root user runs in user mode and switches to kernel mode when needed and then back to user mode (it goes back and forth)
|
||||
source : https://stackoverflow.com/questions/2354125/difference-between-processes-running-in-
|
||||

|
||||
73
joplin notion extension/Web Development/Basics/Tor.md
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
Tor (The Onion Router)
|
||||
https://www.linkedin.com/pulse/what-does-happen-inside-tor-network-how-work-arun-kl
|
||||
tor_anonymity_expert_guide.mp4 https://files.catbox.moe/dqk06e.mp4
|
||||
|
||||
https://www.reddit.com/r/explainlikeimfive/comments/c5sw4b/eli5_what_is_a_tor_browser_how_does_it_work_and/
|
||||
|
||||
- Let's use a mail analogy. Let's say you want to send an anonymous love letter to someone named Alice. You don't want Alice to know it was you who sent it, and you'd prefer not to let anyone else know you have a crush on Alice either.
|
||||
|
||||
Using a standard browser is like handing your letter directly to Alice. Obviously not going to work.
|
||||
|
||||
Fortunately, there are thousands of strangers who volunteer to run a love letter anonymization network. Out of the thousands of strangers, you randomly select three of them. Let's call them stranger #1, #2, #3.
|
||||
|
||||
So here's what you do: Take your letter addressed to Alice. Place it in an envelope, addressed to stranger #3. And put that envelope into another one addressed to stranger #2, and finally another one addressed to stranger #1.
|
||||
|
||||
Now deliver the envelope to stranger #1. Stranger #1 opens it and finds the envelope addressed to stranger #2, which he delivers accordingly. Stranger #2 opens the next envelope, finding and delivering the envelope addressed to stranger #3. Stranger #3 opens it, finding the letter addressed to Alice, and delivers it to Alice. Since it is illegal to open an envelope not addressed to you, each stranger can only open up one layer. (In Tor, this is cryptographically enforced with math, not postal law.)
|
||||
|
||||
So what's the final result? Stranger #1 knows who sent the letter, but not its contents nor its ultimate destination. Stranger #2 knows neither who sent it, nor the contents, nor the destination. Stranger #3 knows the contents, but not who sent it. Alice also knows the contents but not who sent it. Thus anonymity is achieved: nobody other than you knows both the contents and the sender.
|
||||
|
||||
So that's Tor in a nutshell. There's also a lot of confusion out there about the differences between Tor and VPN. In this analogy, a VPN is like handing your letter to a trusted friend who hands it to Alice. Your friend is in a position of being able to know both contents and sender, so you're putting a lot of faith in your friend (VPN) to not rat you out. But it has the advantage of not letting a stranger (stranger #3) read your letter, and it's simpler with less hops making a VPN more suitable for daily browsing.
|
||||
- Volunteers who host the tor nodes are normally belong to privacy respecting organisation , countries or universities to avoid legal trouble. There r some nodes which r controlled by FBI, NSA and law enforcement to catch criminals too
|
||||
- Understanding techinically
|
||||
to access hidden service of tor when someone visit the onion site it checks with tor database for introduction point then tor magic applies ie relaying through 3 different nodes which r randomly selected and finally it reaches the introduction point. From Introduction point to hidden site again tor magic/circuit happens ie relaying through 3 different nodes then data comes to hidden service right
|
||||
- i2p : like tor there is another one ie i2p. tor has clear net access means any surface web contents like google.com can be accessed and also tor network like onion . in case of i2p only i2p network can be accessed. Also i2p is faster
|
||||
one interesting part is, packages in the i2p network change sizes, which makes it more harder to track and fingerprint
|
||||
tor has registry server for nodes and if that goes down then it would be disaster. Though chances r less bc it is mainatined by tor project. i2p is p2p and is more decentralized than tor
|
||||
|
||||
|
||||
|
||||
## hosting sites in tor
|
||||
https://infosecwriteups.com/hosting-tor-website-on-dark-web-the-safe-way-9890d1947b6a
|
||||
- Installing tor
|
||||
`yay -S tor tor-browser`
|
||||
- In `etc/tor/torrc`
|
||||
Uncomment following
|
||||

|
||||
HiddenServicePort 80 127.0.0.1:PORT. It can be any port number wherever site is hosted in localhost. But 80 must be the one other localhost request will be redirected else site wont run
|
||||
Another error can be faced
|
||||

|
||||
Sometimes this 9050 PORT may not be available so u can change that too
|
||||
- Then finally `sudo tor` anywhere. Make sure run it as root. or use `systemctl start tor`
|
||||
- To get another domain just change the hidden service name
|
||||
In `/etc/tor/torrc`
|
||||
It can be
|
||||
`HiddenServiceDir /var/lib/tor/mysite/` too. Now u will get another onion site tooo start as a `tor` user instead of `root` user
|
||||
- Separate config file
|
||||
U can have a separate orrc file too anywhere in user directory too like `~/.torrc` too
|
||||
Use `tor -f ~/.torrc` to start tor wtith different config
|
||||
- Multiple services running simuntaneouly
|
||||
In torrc file
|
||||
```bash
|
||||
HiddenServiceDir /var/lib/tor/mysite/
|
||||
HiddenServicePort 80 127.0.0.1:20108
|
||||
|
||||
HiddenServiceDir /var/lib/tor/hidden_service/
|
||||
HiddenServicePort 80 127.0.0.1:20100
|
||||
|
||||
```
|
||||
- Starting tor as non root aka as a tor username
|
||||
Starting tor as root can have some security issues
|
||||
`systemctl start tor` is a good way of doing that to start as a tor user instead or root
|
||||
But if we want more customizationa and not stick to default then we can have different torrc file but make sure it is in `etc/tor` directory like `/etc/tor/torrc2`
|
||||
By default config file is set as `/etc/tor/torrc` so to change it we need to edit `/usr/lib/systemd/system/tor.service` file. Its syslink is created when we enable this service at `/etc/systemd/system/multi-user.target.wants/tor.service`,
|
||||
Change it like this
|
||||
```text
|
||||
ExecStartPre=/usr/bin/tor -f /etc/tor/torrc2 --verify-config
|
||||
ExecStart=/usr/bin/tor -f /etc/tor/torrc2
|
||||
```
|
||||
Then to apply changes reload systemctl by
|
||||
`systemctl daemon-reload`
|
||||
and finally restart tor service
|
||||
`systemctl restart tor`
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
certificates
|
||||
|
||||
when we connect to site like github.com it is not a direct connection to github IP, there are so many entries in the middle like router,isp and many route nodes. if any of these entries is compromised then man in the middle attack can take place
|
||||
|
||||
1. dns spoofing : github.com will now lead to another IP. can happen when router or isp is compromised
|
||||
2. arp (address resolution protocol) spoofing : arp maps ipv4 to mac address. this happens in public wifi usually and shared network. attacker will send signal and claim to be router and it will claim victim device to router so now every information will route through attacker device
|
||||
3. ssl/tls stripping. related to 2nd one and in this downgrading security to http.
|
||||
|
||||
Now a trusted certificates can prevent these attacks by giving a identity to all the sites so impersonation becomes impossible. browsers have a list of root CAs (Certificate Authority)which gives mapping of public keys to sites. so lets say public key is 'AAA' and site is github.com and signed by digicert and if man in the middle attack take place then he will never have this public key 'AAA' signed by digicert. (Note: there can me multiple keys ofc but those need to be signed by that CA) so he in case of dns spoofing the wrong ip will have invalid cerificate, connection wont be extablished to impoersonation one ever bcz certificates wont be valid ever.
|
||||
|
||||
What if CA is comprmised by weak private key?
|
||||
then an attacker can generate certificate for his and compormised isp or router can impersonate them by generating certificates using the leaked private key.
|
||||
|
||||
|
||||
9
joplin notion extension/Web Development/Basics/others.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
others
|
||||
|
||||
- licenses
|
||||
https://www.gnu.org/licenses/license-list.en.html
|
||||
- **gpl** : all derieved work must be of gpl license and thus open source . it is a copyleft license
|
||||
**agpl** : for server side apps mainly means only frontend but backend is to be open source too. it is extension of gpl
|
||||
**lgp**l : it is bridge between mit and gpl and is weak copyleft license. it is used for libraries mainly so that people dont have to disclose whole program just bcz for using libraries but any modification done on that library must be released.
|
||||
- mit,bsd : permissive license and anyone can do whatever they want with it but have to mention that it is fork of the project and mention contributors
|
||||
-
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
sample apps
|
||||
|
||||
gui
|
||||
|
||||
Java
|
||||
[java gui.7z](../../../_resources/java%20gui.7z)
|
||||
|
||||
c++
|
||||
[cpp imgui.7z](../../../_resources/cpp%20imgui.7z)
|
||||
|
||||
go
|
||||
fyne
|
||||
[go fyne gui.7z](../../../_resources/go%20fyne%20gui.7z)
|
||||
andlabs
|
||||
[go andlabs gui.7z](../../../_resources/go%20andlabs%20gui.7z)
|
||||
wails
|
||||
[go wails gui.7z](../../../_resources/go%20wails%20gui.7z)
|
||||
|
||||
android
|
||||
[android java app.7z](../../../_resources/android%20java%20app.7z)
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
sample codes
|
||||
|
||||
rust
|
||||
|
||||
building
|
||||
`cargo build --release`
|
||||
simply run
|
||||
`cargo run`
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
Practical 1
|
||||
|
||||
Setting up environment
|
||||
- We need to connect our machine to etherium network.
|
||||
- To able to do transaction to etherium network we need to pay fees called gas which is distributed to miners
|
||||
- As buying ether is so expensive we can connect to test network instead of main network for learning purpose.
|
||||
- So to turn our browser into node for the test network use the metamask extenstion
|
||||
- get free ethers for sepolia network from these faucets https://faucetlink.to/sepolia
|
||||
- to use polygon amoy test network use this to add in metamask config
|
||||
https://support.polygon.technology/support/solutions/articles/82000907114-how-to-add-amoy-network-in-your-wallet-
|
||||
```text
|
||||
Network Name: POLYGON AMOY TESTNET
|
||||
New RPC URL: https://rpc-amoy.polygon.technology/
|
||||
Chain ID: 80002
|
||||
Currency Symbol: MATIC
|
||||
Block Explorer URL: https://www.oklink.com/amoy
|
||||
```
|
||||
faucet for polygon amoy : https://faucet.polygon.technology/
|
||||
- to buy real one
|
||||
https://medium.com/prepo/setting-up-metamask-and-getting-eth-matic-on-polygon-step-by-step-guide-fd55147a0f05
|
||||
|
||||
### Coding
|
||||
- Use remix.etherium.org IDE
|
||||
Create a file named `Bank.sol`
|
||||
```sol
|
||||
// SPDX-License-Identifier: MIT
|
||||
pragma solidity 0.8.25;
|
||||
|
||||
contract Bank {
|
||||
int bal;
|
||||
|
||||
constructor() public {
|
||||
bal = 1;
|
||||
}
|
||||
|
||||
function getBalance() view public returns(int) {
|
||||
return bal;
|
||||
}
|
||||
|
||||
function withdraw(int amt) public {
|
||||
bal = bal - amt;
|
||||
}
|
||||
|
||||
function deposit(int amt) public {
|
||||
bal = bal + amt;
|
||||
}
|
||||
}
|
||||
```
|
||||
- This Bank.sol should be under contracts folder. This file is to be compiled
|
||||
- Also the file named `deploy_with_web3.ts` should be in scripts folder which will deploy it
|
||||
```js
|
||||
// This script can be used to deploy the "Storage" contract using Web3 library.
|
||||
// Please make sure to compile "./contracts/1_Storage.sol" file before running this script.
|
||||
// And use Right click -> "Run" from context menu of the file to run the script. Shortcut: Ctrl+Shift+S
|
||||
|
||||
import { deploy } from './web3-lib'
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const result = await deploy('Bank', [])
|
||||
console.log(`address: ${result.address}`)
|
||||
} catch (e) {
|
||||
console.log(e.message)
|
||||
}
|
||||
})()
|
||||
```
|
||||
- Now run it like this
|
||||

|
||||
- switch to injected metamask instead of remix vm to deploy transaction on our network
|
||||
|
||||
|
||||
### Front end
|
||||
Instead of running it and using it inside remix lets create a separate front end
|
||||
- Two things are required ie ABI from compiler section and Address of Bank(not ours) from 'Deploy and run transaction' section.
|
||||
- Now create html file and type
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="">
|
||||
<input type="text" id="amount">
|
||||
<p id="balance"></p>
|
||||
<button id="deposit">Deposit</button>
|
||||
<button id="withdraw">Withdraw</button>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/gh/ethereum/web3.js@1.0.0-beta.34/dist/web3.min.js"></script>
|
||||
|
||||
|
||||
<script>
|
||||
let contract;
|
||||
|
||||
|
||||
web3= new Web3(web3.currentProvider);
|
||||
// web3= new Web3(ethereum);
|
||||
|
||||
// initialize ABI and address first
|
||||
|
||||
// Contract method will accept 2 parameters ie ABI and contract
|
||||
contract = new web3.eth.Contract(ABI,address);
|
||||
|
||||
// as getBalance is a function so we need to call it and use the call method for that which will return the promise
|
||||
contract.methods.getBalance().call().then( (bal)=>{
|
||||
console.log('balance')
|
||||
document.querySelector("#balance").innerHTML= bal;
|
||||
} )
|
||||
|
||||
depositBtn.addEventListener('click',async()=>{
|
||||
let amt=0;
|
||||
amt = parseInt(inputEle.value);
|
||||
|
||||
await window.ethereum.enable();
|
||||
// this will return all the promise of accounts of metamask
|
||||
web3.eth.getAccounts().then( accounts=>{
|
||||
|
||||
console.log('accounts: ',accounts)
|
||||
// taking first account
|
||||
const acc = accounts[0];
|
||||
|
||||
// instead of using call method send method is used
|
||||
return contract.methods.deposit(amt).send({from : acc});
|
||||
} )
|
||||
.then(data=>{
|
||||
console.log('data: ',data)
|
||||
})
|
||||
.catch(err=>{
|
||||
console.log('err: ',err)
|
||||
})
|
||||
})
|
||||
|
||||
withdrawBtn.addEventListener('click',async()=>{
|
||||
let amt=0;
|
||||
amt = parseInt(inputEle.value);
|
||||
|
||||
await window.ethereum.enable();
|
||||
// this will return all the promise of accounts of metamask
|
||||
web3.eth.getAccounts().then( accounts=>{
|
||||
|
||||
console.log('accounts: ',accounts)
|
||||
// taking first account
|
||||
const acc = accounts[0];
|
||||
|
||||
// instead of using call method send method is used
|
||||
return contract.methods.withdraw(amt).send({from : acc});
|
||||
} )
|
||||
.then(data=>{
|
||||
console.log('data: ',data)
|
||||
})
|
||||
.catch(err=>{
|
||||
console.log('err: ',err)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
Theory 2
|
||||
|
||||
## Etherium
|
||||
Developed by Vitalik Buterin. Eherium used to use POW but now from sep 2022 it uses POS.
|
||||
**Why Etherium?**
|
||||
Unlike bitcoin which is decentralized cash app(cryptocurrency), etherium if for decentralized apps(dApps). It has concept like EVM(Etherium Virtual Machine). To run softwares in etherium network, EVM is needed. Here Ether is cryptocurrency in etherium network
|
||||
### Smart Contract
|
||||
If there is a company say B from which user A wanna order product. That company may or may not be trusted. Also comapnay B will give commision to delivery service C. But what if delivery C is not trustable and dont deliver product at all.
|
||||
So using **smart contract** means automating the payment so the money will get transferred automatically once the product is delievered to B from A and to C from B
|
||||

|
||||
Benefits
|
||||
- Fast
|
||||
- Secure bcz of blockchain
|
||||
- Trust
|
||||
|
||||
|
||||
### Drawbacks of Blockchain
|
||||
1. Complex : So many terms like consensus,chain, nodes and miners and complex technology, providing coordination.
|
||||
2. Slow : Bitcoin transaction speed is about 7-10 transactions/sec wheras visa is 1000 transactions/sec.
|
||||
3. Bitcoin and etherium is using proof of work which waste so much resources/energy.
|
||||
4. In case of public blockchain it is true that name will be anonymous but how much transaction has taken place will not be anonymous and known to everyone
|
||||
5. 51% attack : if more than 50% of miners r malacious then they can attack the whole blockchain.
|
||||
6. Here is an example about transactions being public
|
||||
https://www.blockchain.com/explorer/addresses/btc/3M6XXpqUc8G8GuHYKQhjAWobo5aGpkdV7u
|
||||
7. Law enforcement requests information from Coinbase all the time. See https://www.coinbase.com/blog/transparency-report-2023
|
||||
|
||||
### Hyperledger
|
||||
Hyperledger is an open source project having different frameworks and tools to build blockchain. It is hosted in the linux foundation. As public blockchain has its drawbacks so companies and transactions especially B2B instead of B2C want their own blockchain so they start making open source tools for that.
|
||||
Frameworks
|
||||
- Iroha
|
||||
- Sawtooth
|
||||
- Fabric
|
||||
- Indy
|
||||
- Burrow
|
||||
|
||||
Tools
|
||||
- Hyperledger Composer
|
||||
- Hyperledger Cello
|
||||
- Hyperledger Quilt
|
||||
- Hyperledger Explorer
|
||||
121
joplin notion extension/Web Development/Blockchain/Theory.md
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
Theory
|
||||
|
||||
- A blockchain is a distributed ledger with growing lists of records (blocks) that are securely linked together via cryptographic hashes.
|
||||
|
||||
### Web versions
|
||||
- Web 1.0 (1994-2004) : Websites r made by programmers, normal users can read the content only and nothing cant be changed by user. only programmer can write. Also knows as static sites
|
||||
- Web 2.0 (2004-2022) : Websites which allows normal users to both read and write the content and companies provide hosting platform. Also known as dynamic sites. Eg: social media like youtube, facebook. They have centralized servers. Client server architecture. Users dont have control over flow of thir data or ownership
|
||||
- Web 3.0 (2022 - ) : Unlike web 2.0, we have decentralized servers. Peer to peer network. Like torrent services. Applications run on decentralized nodes so those apps are called dapps. Blockchain is the main building block of web 3.0.
|
||||
|
||||
Summary
|
||||
Web 1.0 - Read
|
||||
Web 2.0 - Read and Write
|
||||
Web 3.0 - Own your data
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Someone who made transaction that transaction is stored in ledger and it is immutable
|
||||
|
||||
- Cryptography
|
||||
- Distributed computing : Distributed computing is the method of making multiple computers work together to solve a common problem. It makes a computer network appear as a powerful single computer that provides large-scale resources to deal with complex challenges.
|
||||
- Game theory : game theory, branch of applied mathematics that provides tools for analyzing situations in which parties, called players, make decisions that are interdependent. This interdependence causes each player to consider the other player's possible decisions, or strategies, in formulating strategy.
|
||||
|
||||
### Blockchain
|
||||
If A sends 10$ to B then if ledger is with A or B only then they both may change it for their advantage but if its with all other peers sychronized then they cant change it as others will say hey u changed it
|
||||

|
||||
|
||||
Each block are having data and hash of next node similar to linked list
|
||||

|
||||
Hash algorithms like sha-3 is used to calculate hash of the data so if data changes hash also changes thus breaking the link and helps to identify malicious node
|
||||
|
||||
Miners
|
||||
Miners get the reward for adding blocks in block chain to provide incentivization. But to control the demand as everyone wants to do that for a simple task so in order to choose miners they r given a challenge and that challenge requires computational power and money. Other people who r using block chain r called nodes
|
||||
Summary
|
||||
So basically blockchain is a chain of blocks and each blocks are having multiple transaction and the one who is responsible to add blocks in block chain are called miners(in case of bitcoin). All the people in the blockchain network are called nodes
|
||||
|
||||
### Cryptography
|
||||
Blockchain is very similar to P2P network with the exception of crytpography
|
||||
Reasons for need of crytograpy in block chain
|
||||
1. Confidentiality : A sends a sensitive information to B which should not be read by anyone else
|
||||
2. Integrity : Data sent should not be changed in between by anyone or get corrupted
|
||||
3. Non repudiation : Taking acknowlegement of transaction/message. Eg: If A sends message to B then A cant be able to say that A has not sent it
|
||||
4. Authentication : Means someone else say C cant send message to B inpersonating as A.
|
||||
|
||||
#### Digital signature
|
||||
It is possible to have both digital signature and confidentiality by first encrypting the data from sender's private key then encrypt it again with reciever's public key. When data has reached then first it is decrypted by reciever private key then decrypted by sender public key to verify authenticity.
|
||||

|
||||
|
||||
### Nodes in blockchain
|
||||
- Full Node : Verify blocks which get added. Full node store whole block chain which is like 5450 of GBs in 2024.
|
||||
- Partial Node : lightweight node having partial information. when we use blockchain for wallet so our device becomes node itself
|
||||
- Full node + miner : in this case miner needs huge computational poower lie stack of multiple CPU and GPUs
|
||||
|
||||
### Hashing in blockchain
|
||||
- Input of any length/bit when converted to has using hash function, the hash generated is of fixed bit/size. So even if hige chunk data ie 5gb is passed then only fixed size hash which is merely in bytes will be generated.
|
||||

|
||||
- Unlike encryption hash cant be converted back to input
|
||||
- Some exampples are MD(MD5 was discontinued due to security issue) and SHA where SHA 256 bit is famous. MD stands for Message Digest and SHA stands for Secure Hash Algorithm. SHA is made by NSA
|
||||
- For 2 different inputs we never get same hash and if in rare case if it happens then it is called collision
|
||||
- If we r downloading ubuntu iso from untrusted site then we can generate hash of iso file and compare it with hash posted in original site and if that mismatch then it means it is modified.
|
||||
- For packages having GPG keys, where digital signature is used, hash is signed by encrypting the hash with the key the actual package is not encrypted only its hash is encrypted
|
||||
so to validate it you do 3 steps
|
||||
- you hash it yourself
|
||||
- you decrypt the hash it came with using the key the maintainer gave you
|
||||
- you check if the 2 hashes are the same
|
||||
### Merkle Tree
|
||||
We have nodes and we have transaction in nodes too. As there are multiple transaction we cant store the hash of all transactions so using merkle tree we try to generate single hash for all the transaction.
|
||||
Let's say we have 10 transactions so lets try to merge them in pairs. H1 and H2, H3 and H4 ... and so we will combine hashes.
|
||||

|
||||
If there r even number of nodes then we will just repeat the last one. (9,10) was the odd one out so a copy is created and it become (9,10,9,10).
|
||||
|
||||
|
||||
### Blockchain Architecture
|
||||
- Blocks will contain data but each block will have block header which is like meta-data. Blockheader will contain
|
||||
- Timestamp
|
||||
- Version
|
||||
- Merkle root
|
||||
- Difficulty Target
|
||||
- Nonce
|
||||
- Previous Hash
|
||||
|
||||
Difficulty and Nonce comes under proof of work(POW) section.
|
||||
- Data is immutable bcz of POW as hash will change
|
||||

|
||||
POW
|
||||
- block has to be validated before making change
|
||||
- takes atleast 10 min to add block. So if there r 5 blocks which needs to be changed then it will take atleast 50 min
|
||||
- blockchain stored in multiple machines. Consensus algorithm will be used as it is verified by everyone on blockchain
|
||||
- need supercomputer to change block
|
||||
- need 50% majority in blockchain network which is almost impossible
|
||||
- First block is known as genesis block and is created by the one who started the chain. Its previous hash value is 0.
|
||||
### Types of Blockchain
|
||||
- Public Blockchain
|
||||
1. Open : Means data about is available to public(not secrets but meta-data and other whose visibility is public to everyone)
|
||||
2. Anyone can join that blockchain
|
||||
- Private Blockchain
|
||||
1. For single company
|
||||
- Federated Blockchain
|
||||
1. Group of people/ companies but not to everyone in world
|
||||
|
||||
Advantage of private over public is that there is no need to implement POW to verify nodes as all nodes are known and no need to wait for 10 min.
|
||||
|
||||
### Consensus Blockchain
|
||||
- In order to add a block consensus algorithm is used to determine who will add the block. Some examples are
|
||||
1. POW(Proof of Work) : To solve computational program requiring huge computational power. This algo is used by bitcoin and whoever wins the puzzle will given the opportuity as they have spent computational power.
|
||||
2. POS(Proof of Stake) : Unlike proof of work which is resposible for so much energy consumption. Before applying for that, they put some stake like spending some coins, Used by Etherium
|
||||
3. POET(Prooof of Elapsed Time) : By intel
|
||||
4. Proof of Depsit : Like POS but depositing amount before entering block chain
|
||||
5. Proof of Capacity(POC) : one with huge capacity will win
|
||||
### Proof of Work
|
||||
Why is it useless to alter blocks in bitcoin?
|
||||
|
||||
In a blockchain, each block contains a cryptographic hash of the previous block, creating a chain of blocks linked together. This ensures the integrity and immutability of the blockchain because altering any block would require changing all subsequent blocks, which becomes increasingly difficult as more blocks are added due to the computational effort required (proof of work).
|
||||
|
||||
Let's consider your scenario where you want to change the 25th block in a chain of 30 blocks. To successfully alter the 25th block, you would need to recalculate its hash and the hash of all subsequent blocks in the chain. This is because each block's hash includes the hash of the previous block.
|
||||
|
||||
Additionally, in a proof-of-work system like Bitcoin's, miners compete to solve complex mathematical puzzles to add new blocks to the blockchain. Changing historical blocks would require redoing all the proof-of-work for those blocks and then outpacing the current network's proof-of-work to have the altered version of the blockchain accepted by the majority of nodes.
|
||||
|
||||
The reason it would be considered useless is that the computational power required to achieve this, especially for a significant number of blocks deep in the chain, is prohibitively high. The Bitcoin blockchain, for example, has an immense amount of computational power securing it, making it practically infeasible to alter past transactions without expending an exorbitant amount of resources.
|
||||
|
||||
Even if someone were to succeed in altering the 25th block, the rest of the network would reject it because the altered chain would not have the longest proof-of-work chain, which is the criterion for consensus in Bitcoin and many other blockchain networks. This is why attempting to alter past blocks in a blockchain is often referred to as "useless" because of the immense computational effort required and the near-impossibility of success.
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
Theory3
|
||||
|
||||
### NFT
|
||||
- Non Fungible Token
|
||||
- Anyone can create NFT like first twitter tweet or song. If someone tries to copy it then it would be of no use as new hash will be generated as NFT is unique and have digital signature so others wont have private key so cant really generate same token
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
Setup
|
||||
- use cdn
|
||||
include link and script tags with their links
|
||||
- with syncfusion
|
||||
https://ej2.syncfusion.com/aspnetcore/documentation/getting-started/vscode : important
|
||||
https://help.syncfusion.com/aspnet-core/gettingstarted/getting-started-2-0
|
||||
https://ej2.syncfusion.com/aspnetcore/documentation/nuget-packages
|
||||
to be downloaded from here
|
||||
https://www.nuget.org/packages/Syncfusion.EJ2.AspNet.Core/
|
||||
- licensing
|
||||
- to validate it with license, 2 ways
|
||||
1. entry point file
|
||||
```cs
|
||||
using Syncfusion.Licensing;
|
||||
|
||||
public class Startup
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
// Register the Syncfusion license
|
||||
SyncfusionLicenseProvider.RegisterLicense("YOUR_LICENSE_KEY"); // Replace with your actual license key
|
||||
|
||||
// Other service registrations
|
||||
services.AddControllersWithViews();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
// Existing code for middleware configuration...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. in razor pages
|
||||
```cshtml
|
||||
@using Syncfusion.Licensing
|
||||
@{
|
||||
SyncfusionLicenseProvider.RegisterLicense("YOUR_LICENSE_KEY"); // Replace with your actual license key
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
tips
|
||||
|
||||
- whenever using row, it is recommended to use `m-0` to remove unpredicatable margin.
|
||||
- tabs approach : either spaces between them or white background wit opacity 0.1 to 0.3.
|
||||
https://youtu.be/7vVDxpCY7YY
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
validation
|
||||
|
||||
- for browser default validation for no custom validation rules use something like this
|
||||
```html
|
||||
<form class="needs-valiation">
|
||||
<input type="text" required>
|
||||
</form>
|
||||
```
|
||||
|
||||
```js
|
||||
const forms = document.querySelectorAll(".needs-validation");
|
||||
|
||||
// Loop over them and prevent submission
|
||||
Array.from(forms).forEach((form) => {
|
||||
form.querySelector("input").addEventListener("blur", (e) => {
|
||||
console.log("detected");
|
||||
form.classList.add("was-validated");
|
||||
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
form.addEventListener("submit", (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
console.log("submit listened");
|
||||
// event.preventDefault();
|
||||
// if (!form.checkValidity()) {
|
||||
// console.log("preventing default");
|
||||
// event.preventDefault();
|
||||
// event.stopPropagation();
|
||||
// }
|
||||
|
||||
// form.classList.add("was-validated");
|
||||
});
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
|
||||
Using custom rules for validation
|
||||
19
joplin notion extension/Web Development/CSS/Cards.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
Cards
|
||||
|
||||
```html
|
||||
<div style="display: flex;">
|
||||
<div style="display:flex;flex-direction:column">
|
||||
<div style="padding:100px;margin:10px;box-shadow:0 4px 8px 0 rgba(0,0,0,0.2);border:1px solid #ddd;display:flex;justify-content:center;align-items:center">
|
||||
Users
|
||||
</div>
|
||||
<div style="padding:100px;margin:10px;box-shadow:0 4px 8px 0 rgba(0,0,0,0.2);border:1px solid #ddd;display:flex;justify-content:center;align-items:center">
|
||||
Reviews
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: flex; flex: 1 1 0%;">
|
||||
<div style="padding:100px;margin:10px;box-shadow:0 4px 8px 0 rgba(0,0,0,0.2);border:1px solid #ddd;display:flex;justify-content:center;align-items:center">
|
||||
Notifications
|
||||
</div>
|
||||
</div>
|
||||
</div>;
|
||||
```
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
Custom upload File Button
|
||||
|
||||
```html
|
||||
<input type="file" id="actual-btn"/>
|
||||
<label for="actual-btn">Choose File</label>
|
||||
```
|
||||
|
||||
```css
|
||||
.input{
|
||||
display: none;
|
||||
}
|
||||
|
||||
label {
|
||||
background-color: indigo;
|
||||
color: white;
|
||||
padding: 0.5rem;
|
||||
font-family: sans-serif;
|
||||
border-radius: 0.3rem;
|
||||
cursor: pointer;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
or instead of label div or other element can be used too
|
||||
|
||||
```html
|
||||
<!-- default HTML file upload button -->
|
||||
<input type="file" id="actual-btn" style="display: none;" />
|
||||
|
||||
<!-- custom file upload button using a <button> element -->
|
||||
<div onclick="document.getElementById('actual-btn').click();">Choose File</button>
|
||||
|
||||
```
|
||||
|
||||
24
joplin notion extension/Web Development/CSS/Extras.md
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
Extras
|
||||
|
||||
- superscript
|
||||
```css
|
||||
.superscript {
|
||||
position: relative;
|
||||
top: -0.5em;
|
||||
font-size: 80%;
|
||||
}
|
||||
```
|
||||
- mouseglow
|
||||
https://github.com/anishshobithps/anishshobithps.com/blob/main/src/components/shared/Mouseglow.tsx
|
||||
- uiverse
|
||||
https://uiverse.io/ : library of customizable UI made with css and tailwind
|
||||
- wrapping of characters in word
|
||||
```css
|
||||
.text{
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
```
|
||||
- chartjs
|
||||
https://www.chartjs.org/docs/latest/samples/legend/html.html : for custom html legend
|
||||
https://www.chartjs.org/docs/latest/ : docs
|
||||
|
||||
4
joplin notion extension/Web Development/CSS/Resources.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
Resources
|
||||
|
||||
- https://uiverse.io/ : library of customizable UI made with css and tailwind
|
||||
- tweakcn.com
|
||||
58
joplin notion extension/Web Development/CSS/Snippet links.md
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
Snippet links
|
||||
|
||||
- https://www.facebook.com/100076552205538/posts/pfbid034rP3kxNEFqQU2jYos2jfbv1mwUTfX3kZbLMe3z23U7x92BzHGxrhjz8utFFqcA8Xl/ : Glowing Login Form
|
||||

|
||||

|
||||

|
||||

|
||||
- https://www.facebook.com/100076552205538/posts/pfbid02TSuLtC5v89hCWJKHANqRfLq6iktdixWGVbEFzGhmn71nZqVqKyWu1zdA5gfGrQCxl/ : Animated Skills Bar
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
|
||||
- https://www.facebook.com/100076552205538/posts/pfbid035uybxxxRNiTF3MmPiYN49Ncd8UnHy7Er7fX9EwEoAsG8Hn4LwT1UCy22NifkHRJCl/ : Dynamic Stopwatch
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
- https://www.facebook.com/100076552205538/posts/pfbid02bCCMncYSKD8RLL8krApogqk6NAj9uQjvbqnzgLwzZr9tgx6XRMzEazvXMnAyBz6yl/?app=fbl : Responsive Double Vertical Slider
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
- https://www.facebook.com/100076552205538/posts/pfbid02TEtkpYYQt1kxXDuLhzavafw99rBwWxdXAShXYz2EsaaaYxjWUDMNZMgMvbMnXCgZl/?app=fbl : Digital and Analog Clock Theme
|
||||

|
||||

|
||||

|
||||

|
||||
- https://www.facebook.com/100076552205538/posts/pfbid02TrHUgSbCnUB2ZrJjcY6TyU4Mv4MEJCrnaPWqGmQr8JEdptHHf9Bq4XYmKhwHTMWPl/?app=fbl : Random choice picker using HTML CSS and JavaScript
|
||||
- https://www.facebook.com/100076552205538/posts/pfbid02s5HJkurMTMwA4qPmBMdUD3uKti429cooyppwtx16zUfBKy1mQitnWwuo8wYFWGkcl/ : Animated navigation bar using HTML CSS and JavaScript
|
||||
- https://www.facebook.com/groups/codingthai9/permalink/686919516573076/ : Background Slider
|
||||
- 
|
||||

|
||||

|
||||

|
||||
- https://www.facebook.com/100076552205538/posts/pfbid02PJsKcfcQCZFoMjJ7f8GSszkEXrKJiaNE7gq19pGB4bXSMh1imT4eNogfEPV9P8tWl/ : Responsive movie app using HTML CSS and JavaScript
|
||||
- https://www.facebook.com/100076552205538/posts/pfbid0ajfXteMg4snc8EAW9pEqZZhH6npPYPYmusMXJGR2tJdhP8ekqPZQxSap4LNnbLbel/?app=fbl : Responsive increment counter using HTML CSS and JavaScript
|
||||
- https://www.facebook.com/100076552205538/posts/pfbid02jefi6jVQFYitCZ3YBaF5FadTessjiR4f29hVyokzfp1FrKCKL83Bod2tmet2KxRpl/ : Responsive Login Form
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
- https://www.facebook.com/100076552205538/posts/pfbid02y8iqoGnc9TwseJEMFG8MMn3LcndJgqmdf3VJ7yqodxuMn8r8VnyALspYPaYH4mk4l/ : Social Share Button
|
||||
- https://www.facebook.com/groups/codingthai9/permalink/693400445924983/ : Split Landing page
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
|
||||
- https://www.facebook.com/100076552205538/posts/pfbid0Kk2q1oH2jU7Z8hJVZ3uNSgQioF18wenpUY4WKW7nJV7Z6jxiLXxN46GT4UmN5hwwl/ : Progress Steps Bar
|
||||
- https://www.facebook.com/100076552205538/posts/pfbid02ibjWHEPGTQeEwBYqU6nf1tGDLduSuvNigDtMDMfxFXDtWY9CBYkTvhdr2UuFBSADl/ : Creating a heart
|
||||
|
||||
|
||||
295
joplin notion extension/Web Development/CSS/Snippets/Login.md
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
Login
|
||||
|
||||
```html
|
||||
<!--<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
|
||||
<style id="webmakerstyle">
|
||||
body{
|
||||
background-color: steelblue;
|
||||
color: white;
|
||||
font-family: 'Muli', sans-serif;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.container{
|
||||
background-color: rgba(0,0,0,0.4);
|
||||
padding : 20px 40px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.container h1{
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.container a{
|
||||
text-decoration: none;
|
||||
color: lightblue;
|
||||
}
|
||||
|
||||
.btn{
|
||||
cursor: pointer;
|
||||
display :inline-block;
|
||||
width: 100%;
|
||||
background: lightblue;
|
||||
padding: 15px;
|
||||
font-family: inherit;
|
||||
font-size: 16px;
|
||||
border: 0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.btn:focus{
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.btn:active{
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.text{
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.form-control{
|
||||
position: relative;
|
||||
margin : 20px 0 40px;
|
||||
width : 300px;
|
||||
}
|
||||
|
||||
.form-control input{
|
||||
background-color : transparent;
|
||||
border: 0;
|
||||
border-bottom: 2px solid lightblue;
|
||||
/* border-bottom-color : lightblue; */
|
||||
|
||||
display : block;
|
||||
width : 100%;
|
||||
padding: 15px 0;
|
||||
font-size : 18px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.form-control input:focus,
|
||||
.form-control input:valid{
|
||||
|
||||
outline: 0;
|
||||
border-bottom-color : lightblue;
|
||||
}
|
||||
|
||||
.form-control label{
|
||||
position : absolute;
|
||||
top: 15px;
|
||||
left : 0;
|
||||
pointer-events : none;
|
||||
color: lightgray;
|
||||
font-size: 18px;
|
||||
transition: 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
||||
}
|
||||
|
||||
.form-control label {
|
||||
display : inline-block;
|
||||
font-size : 18px;
|
||||
min-width : 5px;
|
||||
transition : 0.3s cubic-bezier(0.68,-0.55,0.265,1.55);
|
||||
}
|
||||
|
||||
.form-control input:focus ~ label ,
|
||||
.form-control input:valid ~ label {
|
||||
color: lightblue;
|
||||
transform : translateY(-30px);
|
||||
}
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Please Login</h1>
|
||||
<form action="">
|
||||
<div class="form-control">
|
||||
<input type="text" required>
|
||||
<label for="">Email</label>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<input type="password" required>
|
||||
<label for="">Password</label>
|
||||
</div>
|
||||
|
||||
<button class="btn">Login</button>
|
||||
|
||||
<p class="text">Don't have an account? <a href="#">Register</a></p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// const labels=document.querySelectorAll('.form-control label')
|
||||
//
|
||||
// labels.forEach(label=>{
|
||||
// label.innerHTML=label.innerText.split('').map( (letter,idx)=> `span style="transition-delay:${idx*50}ms">${letter}</span> ` ).join('')
|
||||
// })
|
||||
// # sourceURL=userscript.js
|
||||
</script>
|
||||
</body>
|
||||
</html>-->
|
||||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
|
||||
<style id="webmakerstyle">
|
||||
body {
|
||||
background-color: #f0f0f0; /* Light background for the body */
|
||||
color: #333; /* Dark text color for readability */
|
||||
font-family: 'Muli', sans-serif;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
background-color: #ffffff; /* White background for the container */
|
||||
padding: 20px 40px;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); /* Optional: add subtle shadow for depth */
|
||||
}
|
||||
|
||||
.container h1 {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.container a {
|
||||
text-decoration: none;
|
||||
color: #333; /* Dark color for links */
|
||||
}
|
||||
|
||||
.container a:hover{
|
||||
color : grey;
|
||||
}
|
||||
|
||||
.btn {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
background: #333; /* Dark background for button */
|
||||
color: #fff; /* White text color for button */
|
||||
padding: 15px;
|
||||
font-family: inherit;
|
||||
font-size: 16px;
|
||||
border: 0;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.btn:hover{
|
||||
background-color: #111;
|
||||
}
|
||||
|
||||
.btn:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.text {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
position: relative;
|
||||
margin: 20px 0 40px;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.form-control input {
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
border-bottom: 2px solid #333; /* Black border for input fields */
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 15px 0;
|
||||
font-size: 18px;
|
||||
color: #333; /* Dark text color for input fields */
|
||||
}
|
||||
|
||||
.form-control input:focus,
|
||||
.form-control input:valid {
|
||||
outline: 0;
|
||||
border-bottom-color: #333; /* Black color for border on focus */
|
||||
}
|
||||
|
||||
.form-control label {
|
||||
position: absolute;
|
||||
top: 15px;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
color: #666; /* Gray color for label text */
|
||||
font-size: 18px;
|
||||
transition: 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
||||
}
|
||||
|
||||
.form-control label span {
|
||||
display: inline-block;
|
||||
min-width: 5px;
|
||||
transition: 0.3s cubic-bezier(0.68, -0.55, 0.265, 1.55);
|
||||
}
|
||||
|
||||
.form-control input:focus ~ label span,
|
||||
.form-control input:valid ~ label span {
|
||||
color: #333; /* Black color for label on focus */
|
||||
transform: translateY(-30px);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Please Login</h1>
|
||||
<form action="">
|
||||
<div class="form-control">
|
||||
<input type="text" id="email" required>
|
||||
<label for="email"><span>Email</span></label>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<input type="password" id="password" required>
|
||||
<label for="password"><span>Password</span></label>
|
||||
</div>
|
||||
|
||||
<button class="btn">Login</button>
|
||||
|
||||
<p class="text">Don't have an account? <a href="#">Register</a></p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Uncomment and use the following script if needed for animation
|
||||
// const labels = document.querySelectorAll('.form-control label');
|
||||
// labels.forEach(label => {
|
||||
// label.innerHTML = label.innerText.split('')
|
||||
// .map((letter, idx) => `<span style="transition-delay:${idx * 50}ms">${letter}</span>`)
|
||||
// .join('');
|
||||
// });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
```
|
||||
154
joplin notion extension/Web Development/CSS/Snippets/Overlay.md
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
Overlay
|
||||
|
||||
```html
|
||||
<div className="Overlay">
|
||||
<div className="OverlayBox">
|
||||
<div className="message">
|
||||
<h3>This will delete your question. Are you sure?</h3>
|
||||
</div>
|
||||
|
||||
<div className="actionSection">
|
||||
<div className="ok">
|
||||
<button className="okbtn">Ok</button>
|
||||
</div>
|
||||
<div className="cancel">
|
||||
<button className="cancelbtn">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
```
|
||||
|
||||
```scss
|
||||
.Overlay {
|
||||
// to overlay over all others
|
||||
z-index: 10;
|
||||
display: flex;
|
||||
position: fixed;
|
||||
// position: absolute;
|
||||
top: 0;
|
||||
// position: relative;
|
||||
width: 100vw;
|
||||
min-height: 100vh;
|
||||
min-height: 100%;
|
||||
// height: 100vh;
|
||||
// min-height: fit-content;
|
||||
// height: min(100vh, fit-content);
|
||||
background-color: rgba($color: #000000, $alpha: 0.8);
|
||||
|
||||
.OverlayBox {
|
||||
// when height is too so reducing its height to make it scrollable. has issues but best workaround
|
||||
max-height: 100vh;
|
||||
overflow-y: auto;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
background-color: white;
|
||||
width: 300px;
|
||||
aspect-ratio: 2/1;
|
||||
// position: fixed;
|
||||
// position: absolute;
|
||||
position: relative;
|
||||
|
||||
// inset: 0;
|
||||
|
||||
margin: auto;
|
||||
padding: 0.5rem;
|
||||
border: 10px solid grey;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 4px 8px rgba($color: white, $alpha: 0.2);
|
||||
|
||||
.message {
|
||||
color: $navColor;
|
||||
}
|
||||
|
||||
.actionSection {
|
||||
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
||||
// occupying rest of space so to push ok and cancel at end
|
||||
r// both horizontally and vertically
|
||||
flex: 1;
|
||||
align-items: flex-end;
|
||||
justify-content: flex-end;
|
||||
|
||||
.ok,
|
||||
.cancel {
|
||||
margin: 0.3rem;
|
||||
|
||||
button {
|
||||
@include buttonDim;
|
||||
padding: 0.4rem;
|
||||
width: 4rem;
|
||||
}
|
||||
}
|
||||
|
||||
.ok button:hover {
|
||||
background-color: $correct-ans-color;
|
||||
}
|
||||
|
||||
.cancel button:hover {
|
||||
background-color: $wrong-ans-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include media-xs-400-height {
|
||||
.Overlay {
|
||||
.OverlayBox {
|
||||
// max-width: 300px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
```jsx
|
||||
import "./Overlay.scss";
|
||||
|
||||
function Overlay(props) {
|
||||
const { isOverlayVisible, setIsOverlayVisible, message, children } = props;
|
||||
|
||||
console.log("children :", children);
|
||||
|
||||
const cancelEvent = () => {
|
||||
setIsOverlayVisible(false);
|
||||
};
|
||||
|
||||
const okEvent = () => {
|
||||
setIsOverlayVisible(false);
|
||||
};
|
||||
|
||||
// if no children elements then children will be empty object
|
||||
return (
|
||||
<div className="Overlay">
|
||||
<div className="OverlayBox">
|
||||
<div className="message">
|
||||
<h3>{message}</h3>
|
||||
</div>
|
||||
{children ? children : <></>}
|
||||
|
||||
<div className="actionSection">
|
||||
<div className="ok">
|
||||
<button className="okbtn" onClick={okEvent}>
|
||||
Ok
|
||||
</button>
|
||||
</div>
|
||||
<div className="cancel">
|
||||
<button className="cancelbtn" onClick={cancelEvent}>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Overlay;
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,240 @@
|
|||
Questions with answers ui
|
||||
|
||||
```html
|
||||
<div className="ShowQuizMain">
|
||||
<div className="ShowQuizSection">
|
||||
<div className="extraButtonsSection">
|
||||
<div className="expandAll">
|
||||
<button>Expand All</button>
|
||||
</div>
|
||||
<div className="collapseAll">
|
||||
<button>Collapse All</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="QuestionBox">
|
||||
<div className="headerSection">
|
||||
<div className="col1">
|
||||
<h4 className="technologyText"> Technology : Java</h4>
|
||||
</div>
|
||||
<div className="col2">
|
||||
<div className="update">
|
||||
<button title="edit">
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="delete">
|
||||
<button title="delete">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="QuestionBox_Question">
|
||||
<div className="QuestionBox_Question_Text">
|
||||
1. What is Java? What is Java? What is Java? What is Java? What is
|
||||
Java? What is Java? What is Java? What is Java? What is Java? What
|
||||
is Java? What is Java? What is Java? What is Java?
|
||||
</div>
|
||||
<button className="toggleAnsBtn">
|
||||
<i className="arrow up"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div className="QuestionBox_Options_Container">
|
||||
<div className="QuestionBox_Options visible">
|
||||
<div className="QuestionBox_Options_Option">
|
||||
a. Java is object oriented language
|
||||
</div>
|
||||
<div className="QuestionBox_Options_Option correct">
|
||||
b. Java is not an object oriented language
|
||||
</div>
|
||||
|
||||
<div className="QuestionBox_Options_Option">
|
||||
c. Java is annoying
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```scss
|
||||
@import "../config";
|
||||
|
||||
@import "./Arrows";
|
||||
.ShowQuizMain {
|
||||
padding-top: 20px;
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
background-color: $dimwhite;
|
||||
min-height: 500px;
|
||||
|
||||
.ShowQuizSection {
|
||||
width: 70%;
|
||||
padding: 0 0.5rem;
|
||||
min-width: 500px;
|
||||
background-color: white;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); // Added subtle shadow
|
||||
|
||||
.extraButtonsSection {
|
||||
width: 100%;
|
||||
padding: 1rem;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
.expandAll,
|
||||
.collapseAll {
|
||||
margin: 0 1rem;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); // Added subtle shadow
|
||||
|
||||
button {
|
||||
cursor: pointer;
|
||||
padding: 0.5rem 1rem;
|
||||
border: none;
|
||||
border: 1px solid black;
|
||||
border-radius: 3px;
|
||||
background-color: transparent;
|
||||
|
||||
&:hover {
|
||||
background-color: $dimwhite;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ShowQuizSection .QuestionBox {
|
||||
// overflow: hidden;
|
||||
margin: 1rem auto;
|
||||
// padding-top: 2rem;
|
||||
width: 70%;
|
||||
|
||||
.headerSection {
|
||||
display: flex;
|
||||
border-top: 1px solid black;
|
||||
background-color: whitesmoke;
|
||||
|
||||
.technologyText {
|
||||
padding: 0.1rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.update button,
|
||||
.delete button {
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
padding: 0.3rem;
|
||||
font-size: 1rem;
|
||||
transition: all 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
.delete button:hover {
|
||||
background-color: $delete-btn-hover;
|
||||
}
|
||||
|
||||
.update button:hover {
|
||||
background-color: $edit-btn-hover;
|
||||
}
|
||||
|
||||
.update {
|
||||
margin-right: 0.2rem;
|
||||
}
|
||||
|
||||
.col1,
|
||||
.col2 {
|
||||
width: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.col2 {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
&_Question {
|
||||
position: relative;
|
||||
// background-color: $navColor;
|
||||
border: 1px solid $dimwhite;
|
||||
background-color: white;
|
||||
border-radius: 5px;
|
||||
padding: 0.5rem 1rem;
|
||||
padding-right: 2rem;
|
||||
// color: white;
|
||||
color: black;
|
||||
line-height: 1.5rem;
|
||||
|
||||
.toggleAnsBtn {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
bottom: 15px;
|
||||
|
||||
transform: scale(1.2);
|
||||
|
||||
padding: 0 4px;
|
||||
|
||||
// color: white;
|
||||
color: black;
|
||||
border: none;
|
||||
// background-color: rgba($color: white, $alpha: 0.1);
|
||||
background-color: rgba($color: black, $alpha: 0.1);
|
||||
// background-color: transparent;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
&_Options_Container {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&_Options {
|
||||
// width: 99%;
|
||||
margin: 0 auto;
|
||||
// box-sizing: border-box;
|
||||
transform: translateY(-100%);
|
||||
transition: all 0.3s ease-in-out;
|
||||
|
||||
padding: 0.5rem 0rem;
|
||||
// color: white;
|
||||
color: black;
|
||||
// background-color: $dimwhite;
|
||||
background-color: $options-bg-color;
|
||||
|
||||
&_Option {
|
||||
background-color: $wrong-ans-color;
|
||||
padding: 0.75rem;
|
||||
margin: 0.5rem;
|
||||
border-radius: 5px;
|
||||
|
||||
&.correct {
|
||||
background-color: $correct-ans-color;
|
||||
}
|
||||
}
|
||||
|
||||
&.visible {
|
||||
transform: translateY(0%);
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// config.scss
|
||||
$navColor: rgba(20, 20, 20, 0.9);
|
||||
$dimwhite: rgb(220, 220, 220);
|
||||
$wrong-ans-color: rgba(#ba0021, 0.3);
|
||||
$correct-ans-color: rgba(green, 0.3);
|
||||
$options-bg-color: rgba(
|
||||
$color: grey,
|
||||
$alpha: 0.2,
|
||||
);
|
||||
|
||||
$delete-btn-hover: rgba(red, 0.3);
|
||||
$edit-btn-hover: rgba(blue, 0.3);
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
Rotating arrow
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<style>
|
||||
.arrow {
|
||||
border: solid black;
|
||||
border-width: 0 3px 3px 0;
|
||||
display: inline-block;
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.right {
|
||||
transform: rotate(-45deg);
|
||||
-webkit-transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.left {
|
||||
transform: rotate(135deg);
|
||||
-webkit-transform: rotate(135deg);
|
||||
}
|
||||
|
||||
.up {
|
||||
transform: rotate(-135deg);
|
||||
-webkit-transform: rotate(-135deg);
|
||||
}
|
||||
|
||||
.down {
|
||||
transform: rotate(45deg);
|
||||
-webkit-transform: rotate(45deg);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h2>CSS Arrows</h2>
|
||||
|
||||
<p>arrow: <i class="arrow"></i></p>
|
||||
<p>Right arrow: <i class="arrow right"></i></p>
|
||||
<p>Left arrow: <i class="arrow left"></i></p>
|
||||
<p>Up arrow: <i class="arrow up"></i></p>
|
||||
<p>Down arrow: <i class="arrow down"></i></p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
Sidepanel
|
||||
|
||||
```html
|
||||
<div class="sidePanel">
|
||||
<div class="userList">
|
||||
<div class="userItem" onclick="toggleQuizzes('user1')">
|
||||
User 1
|
||||
</div>
|
||||
<div class="userQuizzes" id="user1">
|
||||
<ul>
|
||||
<li>Quiz 1</li>
|
||||
<li>Quiz 2</li>
|
||||
<li>Quiz 3</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="userItem" onclick="toggleQuizzes('user2')">
|
||||
User 2
|
||||
</div>
|
||||
<div class="userQuizzes" id="user2">
|
||||
<ul>
|
||||
<li>Quiz A</li>
|
||||
<li>Quiz B</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="userItem" onclick="toggleQuizzes('user2')">
|
||||
User 2
|
||||
</div>
|
||||
<div class="userQuizzes" id="user2">
|
||||
<ul>
|
||||
<li>Quiz A</li>
|
||||
<li>Quiz B</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
```css
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
.sidePanel {
|
||||
width: 200px;
|
||||
height: 100vh;
|
||||
background-color: #f4f4f4;
|
||||
box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1);
|
||||
overflow-y: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
// transform: translateX(-100%);
|
||||
}
|
||||
|
||||
.userList {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.userItem {
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 10px;
|
||||
padding: 10px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
|
||||
.userItem:hover {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
.userQuizzes {
|
||||
display: none;
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.userQuizzes ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.userQuizzes li {
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
confirmation feature on button without js
|
||||
|
||||
```html
|
||||
<form action="/register" method="POST">
|
||||
<!-- Registration Fields -->
|
||||
<label for="username">Username:</label>
|
||||
<input type="text" id="username" name="username" required>
|
||||
|
||||
<label for="password">Password:</label>
|
||||
<input type="password" id="password" name="password" required>
|
||||
|
||||
<!-- The CSS Hack Trigger -->
|
||||
<div class="submit-wrapper">
|
||||
<input type="checkbox" id="unlock-submit" class="toggle-gate">
|
||||
<label for="unlock-submit" class="cover-button">Register</label>
|
||||
<button type="submit" class="real-button">Confirm Registration</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<style>
|
||||
.submit-wrapper {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
/* Hide the actual checkbox */
|
||||
.toggle-gate {
|
||||
display: none;
|
||||
}
|
||||
/* The fake button that sits on top */
|
||||
.cover-button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #007bff;
|
||||
color: white;
|
||||
text-align: center;
|
||||
line-height: 35px;
|
||||
cursor: pointer;
|
||||
z-index: 2;
|
||||
}
|
||||
/* The real submit button hidden underneath */
|
||||
.real-button {
|
||||
padding: 8px 16px;
|
||||
background: #28a745;
|
||||
color: white;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
/* When the fake button is clicked, it checks the box and hides itself */
|
||||
.toggle-gate:checked ~ .cover-button {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
tailwind
|
||||
|
||||
```html
|
||||
<form action="/register" method="POST" class="max-w-md mx-auto p-6 bg-white rounded-lg shadow-md space-y-4">
|
||||
<!-- Registration Fields -->
|
||||
<div>
|
||||
<label for="username" class="block text-sm font-medium text-gray-700 mb-1">Username</label>
|
||||
<input type="text" id="username" name="username" required class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="password" class="block text-sm font-medium text-gray-700 mb-1">Password</label>
|
||||
<input type="password" id="password" name="password" required class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
|
||||
</div>
|
||||
|
||||
<!-- The CSS Hack Trigger Container -->
|
||||
<div class="relative inline-block w-full pt-2">
|
||||
<!-- Hidden Checkbox using Tailwind's peer utility -->
|
||||
<input type="checkbox" id="unlock-submit" class="peer hidden">
|
||||
|
||||
<!-- First Click: The Fake Button Label -->
|
||||
<label for="unlock-submit" class="absolute inset-x-0 bottom-0 top-2 flex items-center justify-center bg-blue-600 hover:bg-blue-700 text-white font-semibold py-2 px-4 rounded-md cursor-pointer z-10 transition-colors peer-checked:hidden">
|
||||
Register
|
||||
</label>
|
||||
|
||||
<!-- Second Click: The Real Submit Button -->
|
||||
<button type="submit" class="w-full bg-green-600 hover:bg-green-700 text-white font-semibold py-2 px-4 rounded-md transition-colors">
|
||||
Confirm Registration
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
custom dropdown with bootstrap
|
||||
```html
|
||||
|
||||
<style>
|
||||
.mh-250{
|
||||
max-height: 250px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="btn-group w-100 border">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary bg-transparent text-black fs-5 border-0 text-start"
|
||||
>
|
||||
--Select--
|
||||
</button>
|
||||
<button
|
||||
style="max-width: 50px"
|
||||
class="btn btn-secondary dropdown-toggle dropdown-toggle-split p-2 bg-transparent text-black fit-content fs-5 border-0"
|
||||
type="button"
|
||||
id="dropdownMenuButton1"
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
></button>
|
||||
|
||||
<ul
|
||||
class="dropdown-menu mh-250 overflow-auto w-100"
|
||||
id="yearSelect"
|
||||
aria-labelledby="dropdownMenuButton1"
|
||||
>
|
||||
<li><a class="dropdown-item" href="#">--Select-- </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
```
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
files
|
||||
|
||||
[editForm.html](../../../../_resources/editForm.html)
|
||||

|
||||
[editForm2.html](../../../../_resources/editForm2.html)
|
||||

|
||||
[tabsAtTtop.html](../../../../_resources/tabsAtTtop.html)
|
||||

|
||||
195
joplin notion extension/Web Development/CSS/Tailwind/Extras.md
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
Extras
|
||||
- with `npx tailwindcss init --full` we can have full configuratio of properties available at `tailwind.config.js` and we can add some properties with their values too like
|
||||
```js
|
||||
// in theme
|
||||
fontSize: {
|
||||
mammoth: ["10rem", { lineHeight: "1" }],
|
||||
xs: ["0.75rem", { lineHeight: "1rem" }],
|
||||
sm: ["0.875rem", { lineHeight: "1.25rem" }],
|
||||
base: ["1rem", { lineHeight: "1.5rem" }],
|
||||
lg: ["1.125rem", { lineHeight: "1.75rem" }],
|
||||
xl: ["1.25rem", { lineHeight: "1.75rem" }],
|
||||
"2xl": ["1.5rem", { lineHeight: "2rem" }],
|
||||
"3xl": ["1.875rem", { lineHeight: "2.25rem" }],
|
||||
"4xl": ["2.25rem", { lineHeight: "2.5rem" }],
|
||||
"5xl": ["3rem", { lineHeight: "1" }],
|
||||
"6xl": ["3.75rem", { lineHeight: "1" }],
|
||||
"7xl": ["4.5rem", { lineHeight: "1" }],
|
||||
"8xl": ["6rem", { lineHeight: "1" }],
|
||||
"9xl": ["8rem", { lineHeight: "1" }],
|
||||
},
|
||||
```
|
||||
here under fontSize we added mammoth so when we type `text-mammoth` in html we will get font-size as 10rem with line-height of similar size(10 rem in this case).
|
||||
- instead of directly modyfying full tailwind.config.js we can do same with empty one which is created without using `full` flag.
|
||||
```js
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ["./public/**/*.{html,js}"],
|
||||
theme: {c
|
||||
extend: {
|
||||
colors: {
|
||||
primary: "#FF6363",
|
||||
secondary: {
|
||||
100: "#E2E2D5",
|
||||
200: "888883",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
|
||||
```
|
||||
in html
|
||||
```html
|
||||
<ul>
|
||||
<li
|
||||
class="text-blue-900 font-bold text-xl p-4 m-4 border-2 border-solid border-gray-400"
|
||||
>
|
||||
<a href="#">
|
||||
<span>Home</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
<span
|
||||
class="bg-secondary-100 text-secondary-200"
|
||||
>About</span
|
||||
>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
|
||||
- **custom fonts**
|
||||
in src/style.css import the font with CDN like this
|
||||
```css
|
||||
@import url(https://cdn.jsdelivr.net/fontsource/fonts/nunito:vf@latest/latin-wght-normal.woff2);
|
||||
```
|
||||
then in tailwind.config.js add this
|
||||
```js
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ["./public/**/*.{html,js}"],
|
||||
theme: {
|
||||
extend: {
|
||||
fontFamily: {
|
||||
body: ["Nunito"],
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
|
||||
```
|
||||
finally in html
|
||||
`<body class="font-body">` this will add the font 'Nunito'
|
||||
|
||||
- **@apply Directive**
|
||||
just like mixin in sass we can use apply directive to inherit the properties of other classs
|
||||
in src/styles.css
|
||||
```css
|
||||
@import url(https://cdn.jsdelivr.net/fontsource/fonts/nunito:vf@latest/latin-wght-normal.woff2);
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
.card {
|
||||
@apply relative bg-white rounded overflow-hidden shadow-md;
|
||||
}
|
||||
|
||||
.badge {
|
||||
@apply bg-secondary-100 text-secondary-200 text-xs uppercase font-bold rounded-full p-2 absolute top-0 ml-2 mt-2;
|
||||
}
|
||||
|
||||
```
|
||||
in public/index.html
|
||||
```html
|
||||
<div class="card">
|
||||
<img
|
||||
class="w-full h-32 sm:h-48 object-cover"
|
||||
src="img/stew.png"
|
||||
alt="stew"
|
||||
/>
|
||||
<div>
|
||||
<span class="font-bold">5 Bean Chili Stew</span>
|
||||
<span class="block text-gray-500 text-sm"
|
||||
>Recipe by Mario</span
|
||||
>
|
||||
</div>
|
||||
<div class="badge">
|
||||
<span>25 mins</span>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
to fix bluish nature when using gray do this
|
||||
```js
|
||||
const colors = require('tailwindcss/colors')
|
||||
|
||||
module.exports = {
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
// This overrides 'gray' classes to use the flat 'neutral' color palette instead
|
||||
gray: colors.neutral,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
- **Tailwind components**
|
||||
https://merakiui.com/components
|
||||
https://daisyui.com/
|
||||
https://demos.creative-tim.com/soft-ui-design-system/presentation.html
|
||||
https://www.hyperui.dev/
|
||||
https://daily.dev/blog/10-free-tailwind-css-ui-kits-and-component-libraries-2024
|
||||
[10 Free Tailwind CSS UI Kits & Component Libraries 2024 (15_3_2025 11_21_40 pm).u.zip.html](../../../../_resources/10%20Free%20Tailwind%20CSS%20UI%20Kits%20&%20Component%20Libraries.html)
|
||||
|
||||
|
||||
|
||||
|
||||
for !important use this
|
||||
|
||||
`ml-auto` to `!ml-auto`
|
||||
|
||||
tailwind group
|
||||
eg:
|
||||
```html
|
||||
<div class="group bg-blue-200 p-4">
|
||||
<p class="text-blue-800 group-hover:text-red-500">Hover over me!</p>
|
||||
<button class="bg-gray-300 group-hover:bg-green-500">Click me</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
tailwind peer class
|
||||
The peer class in Tailwind CSS is a modifier used to style an element based on the state of its sibling elements. Group allows child elements to react to the state of their parent
|
||||
Peer allows an element to react to the state of its sibling.
|
||||

|
||||
```html
|
||||
<div class="pill">
|
||||
<input type="checkbox" class="peer hidden" name="che1" id="che1" >
|
||||
|
||||
<label for="che1" class="max-w-[300px] opacity-50 peer-checked:opacity-100 cursor-pointer hover:opacity-80 border border-gray-500 items-center gap-1 bg-gray-200 text-gray-800 rounded-full px-2.5 py-0.5 text-sm" >
|
||||
<span class="whitespace-nowrap truncate ">
|
||||
rockdsadsadsd dsa ssafdd fdssdfsadsa sds sd dsf dfd fds rockdsadsadsd dsa ssafdd fdssdfsadsa sds sd dsf dfd fds
|
||||
|
||||
</span>
|
||||
</label>
|
||||
|
||||
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
to increase specificity
|
||||
using `[&&]` or `[&]`
|
||||
`<div class="m-10 border border-slate-200 [&&]:border-rose-500">Foo`
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
Fonts and Colors
|
||||
https://tailwindcss.com/docs
|
||||
|
||||
- Text colors
|
||||
`text-<color_name>-<strength>`
|
||||
eg: `text-yellow-500`
|
||||
highter strength means more darker it is.
|
||||
- font-size
|
||||
Syntax : `text-<sizeLabel>`
|
||||
`text-large`, `text-xl`, `text-6xl`,`text-2xl`
|
||||
- bold
|
||||
`font-bold`, `font-semibold`
|
||||
|
||||
|
||||
**Padding , margin and borders**
|
||||
- `p-1`, `p-2` , `p-3` , `p-4` with padding equivalent of 0.25rem, 0.5rem, 0.75rem , 1 rem
|
||||
for padding at vertical means for top,down => `py-4`
|
||||
for padding at horizontal means for left,right => `px-4`
|
||||
for at top => `pt-4`. similarly for right, bottom, left => `pr`, `pb`, `pl`.
|
||||
- for margin, replace `p` with `m`.
|
||||
- for border,
|
||||
`border` for border of width 1px , `border-2` => width : 2px
|
||||
`border-y` : border-top and border-bottom will be there of width 1px
|
||||
`border-x` : border-left and border-right will be there of width 1px
|
||||
similarly for individual directions
|
||||
`border-t-4`, `border-r-4`, `border-b-4` and `border-l-4`
|
||||
for border style
|
||||
`border-solid`
|
||||
for border color
|
||||
`border-blue-200` , `border-gray-400`
|
||||
|
||||
|
||||
**Sizing**
|
||||
- `size-full` => `width: 100%; height: 100%`
|
||||
`size-fit` => `width: fit-content; height: fit-content`
|
||||
`size-6/12` => `width: 50%; height: 50%`
|
||||
|
||||
|
||||
**flex layout**
|
||||
```html
|
||||
<div class="flex items-end justify-center">
|
||||
<div class="bg-red-500 h-4 w-6"></div>
|
||||
<div class="bg-blue-500 h-8 w-6"></div>
|
||||
<div class="bg-green-500 h-12 w-6"></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
|
||||
**responsive classes**
|
||||
- in tailwind.configs.js
|
||||
```js
|
||||
module.exports= {
|
||||
theme : {
|
||||
screens : {
|
||||
'sm': '640px',
|
||||
// => @media (min-width: 640px){...}
|
||||
'md': '768px',
|
||||
'lg': '1024px',
|
||||
'xl': '1280px'
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
in html
|
||||
`<a href="/" class="text-green-500 sm:text-red-500 lg:text-blue-500">Food Ninja</a>`
|
||||
So as width keeps increasing color will change from green to red to blue
|
||||
|
||||
|
||||
**Cards**
|
||||
```html
|
||||
<!-- cards go here -->
|
||||
<div class="bg-white rounded overflow-hidden shadow-md">
|
||||
<img
|
||||
class="w-full h-32 sm:h-48 object-cover"
|
||||
src="img/stew.png"
|
||||
alt="stew"
|
||||
/>
|
||||
<div>
|
||||
<span class="font-bold">5 Bean Chili Stew</span>
|
||||
<span class="block text-gray-500 text-sm"
|
||||
>Recipe by Mario</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
**Badge**
|
||||
- badges are small visual indicators or labels that convey information or denote status on cards. They can serve various purposes, such as status indicator, classification,etc
|
||||
```html
|
||||
<div
|
||||
class="relative bg-white rounded overflow-hidden shadow-md"
|
||||
>
|
||||
<img
|
||||
class="w-full h-32 sm:h-48 object-cover"
|
||||
src="img/stew.png"
|
||||
alt="stew"
|
||||
/>
|
||||
<div>
|
||||
<span class="font-bold">5 Bean Chili Stew</span>
|
||||
<span class="block text-gray-500 text-sm"
|
||||
>Recipe by Mario</span
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="bg-secondary-100 text-secondary-200 text-xs uppercase font-bold rounded-full p-2 absolute top-0 ml-2 mt-2"
|
||||
>
|
||||
<span>25 mins</span>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
- make sure that parent ie card has relative(`postition : relative`) class so badge as absolute would work
|
||||
|
||||
|
||||
**Grids**
|
||||
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
HTML Template
|
||||
|
||||
- By linking style.css of tailwind, all the default styles of elements imposed by browser will be gone
|
||||
```html
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Document</title>
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<div>
|
||||
<nav>
|
||||
<div>
|
||||
<h1>
|
||||
<a href="/">Food Ninja</a>
|
||||
</h1>
|
||||
</div>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="#">
|
||||
<span>Home</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
<span>About</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#">
|
||||
<span>Contact</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<main>
|
||||
<div>
|
||||
<a href="#">Log in</a>
|
||||
<a href="#">Sign up</a>
|
||||
</div>
|
||||
|
||||
<header>
|
||||
<h2>Recipes</h2>
|
||||
<h3>For Ninjas</h3>
|
||||
</header>
|
||||
|
||||
<div>
|
||||
<h4>Latest Recipes</h4>
|
||||
|
||||
<div>
|
||||
<!-- cards go here -->
|
||||
<div>
|
||||
<img src="img/stew.jpg" alt="stew" />
|
||||
<div>
|
||||
<span>5 Bean Chili Stew</span>
|
||||
<span>Recipe by Mario</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4>Most Popular</h4>
|
||||
|
||||
<div>
|
||||
<!-- cards go here -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div>Load more</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
Without linking tailwind style file
|
||||

|
||||
|
||||
With linking tailwind style file
|
||||

|
||||
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
Intro and Setup
|
||||
https://www.youtube.com/playlist?list=PL4cUxeGkcC9gpXORlEHjc5bgnIi5HEGhw
|
||||
|
||||
- Css framwork made of utility classes and are much lower level than Bootstrap, Materialize etc for improved flexibility
|
||||
|
||||
**Installation**
|
||||
- `npm init -y` to create package.json base file and then `npm i tailwindcss postcss autoprefixer` to install these modules locally
|
||||
|
||||
**How it works**
|
||||

|
||||
in src all the classes of tailwind and importted and tailwind script compiles it to output public style.css files which is interpretated by browser.
|
||||
We can also add our styles in src file too but that is not needed often
|
||||
|
||||
### Setup
|
||||
- Create directory named `src` and `public` and inside `src` add `style.css` and add followiing code
|
||||
```css
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
```
|
||||
- Also do `npx tailwindcss init` and add following in `tailwind.config.js`
|
||||
```js
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: ["./public/**/*.{html,js}"],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
||||
|
||||
```
|
||||
If html file is int public folder then it is public/** ... . if its in src then it is src/**..
|
||||
- In package.json under scripts section add the following script
|
||||
`"build-css": "tailwindcss build src/styles.css -o public/styles.css"`
|
||||
- Now run `npm run build-css` to generate style.css at public folder. this public folder may have index.html file too
|
||||
|
||||
- Without npm, in order to use tailwind simply add following cdn link
|
||||
`<link href= "https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet"/>`
|
||||
|
||||
also make sure to install this if there are problems `npm i tailwindcss@3.4.17 --save-dev`
|
||||
|
||||
73
joplin notion extension/Web Development/CSS/Tips.md
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
Tips
|
||||
|
||||
- A css question. If I have a div container whose height is unknown.
|
||||
Inside it we have a nav section whose height we don't know too.
|
||||
How to make sure that next block inside container takes rest of the height.
|
||||
Normally if there is no other block above it then we can simply use height:100% but here it will overflow.
|
||||
```css
|
||||
#parent {
|
||||
display:flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
#secondBlock {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
```
|
||||
To get more info about how flex-1 behaves check the following
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="flex w-500">
|
||||
<div class="flex col ">
|
||||
<div class="users">Users</div>
|
||||
<div class="reviews">Reviews</div>
|
||||
</div>
|
||||
<div class="flex flex-1">
|
||||
<div class="">Notifications</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```css
|
||||
.w-500{
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
.flex{
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.col{
|
||||
flex-direction: column
|
||||
}
|
||||
|
||||
.flex-1{
|
||||
flex: 1;
|
||||
}
|
||||
```
|
||||
|
||||
- there is sidepanel at right side which expand. it have invisible extra width so each item can expand to that when hovered but that invisible portion i dont want it to effect rest of page. and able to interact with. how do i fix it
|
||||
```css
|
||||
.parent{
|
||||
pointer-events : none;
|
||||
}
|
||||
|
||||
.child{
|
||||
pointer-events : auto;
|
||||
}
|
||||
|
||||
.child:hover{
|
||||
...
|
||||
}
|
||||
|
||||
```
|
||||
34
joplin notion extension/Web Development/CSS/bootstrap.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
bootstrap
|
||||
|
||||
**Links**
|
||||
bootstrap class reference
|
||||
https://bootstrapshuffle.com/classes
|
||||
|
||||
docs
|
||||
https://getbootstrap.com/docs/5.0/content/typography/
|
||||
|
||||
**cdn** (all under head tag)
|
||||
```html
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
|
||||
```
|
||||
|
||||
|
||||
**classes**
|
||||
- padding : p-5, px-5,py-2,pt-4, same for margin but starts with m instead of p
|
||||
- font : fs-1, fs-lg-1, fs-md-1
|
||||
- flex : d-flex, justify-content-center
|
||||
- size : w-100,w-auto
|
||||

|
||||
- icons
|
||||
https://icons.getbootstrap.com/
|
||||
- borders
|
||||
border, border-top, border-bottom, border-start,border-end . start for left and end for right
|
||||
- dropdown hover color change
|
||||
```css
|
||||
.dropdown-menu > li > a:hover {
|
||||
background-image: none;
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
```
|
||||
26
joplin notion extension/Web Development/CSS/page rules.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
page rules
|
||||
|
||||
`@page` rule defines the dimension of the page which is gonna be printed. There are a few important things that should be under control when you want to print a web page those are listed below: The page size, orientation, margins, border, and padding
|
||||
```css
|
||||
/* Printing */
|
||||
page {
|
||||
background: white;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 0.5cm;
|
||||
}
|
||||
|
||||
page[size="A4"] {
|
||||
width: 21cm;
|
||||
height: 29.7cm;
|
||||
}
|
||||
|
||||
@page {
|
||||
size: 21cm 29.7cm;
|
||||
padding: 0;
|
||||
margin: 0mm;
|
||||
border: none;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
/* End Printing */
|
||||
```
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
partial border
|
||||
https://unused-css.com/blog/css-partial-borders/
|
||||
|
||||
```html
|
||||
<div class="pseudo-partial-border">Pseudo Partial Border</div>
|
||||
```
|
||||
|
||||
```css
|
||||
.pseudo-partial-border {
|
||||
position: relative;
|
||||
width: 250px;
|
||||
height: 41px;
|
||||
padding: 7px;
|
||||
margin: 25px;
|
||||
background: lightgray;
|
||||
border: none;
|
||||
text-align: center;
|
||||
}
|
||||
```
|
||||
|
||||
Before and after pseudo elements
|
||||
|
||||
```css
|
||||
.pseudo-partial-border::before,
|
||||
.pseudo-partial-border::after {
|
||||
position: absolute;
|
||||
width: 33px;
|
||||
height: 20px;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.pseudo-partial-border::before {
|
||||
left: 0;
|
||||
top: 0;
|
||||
border-left: 3px solid black;
|
||||
border-top: 3px solid black;
|
||||
}
|
||||
|
||||
.pseudo-partial-border::after {
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-right: 3px solid black;
|
||||
border-bottom: 3px solid black;
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
smart width and height (Given solution not working yet)
|
||||
|
||||
- Using min and max we can set the width to be appropriate for dynamic width and height
|
||||
**Update : this wont work**
|
||||
|
||||
for eg:
|
||||
|
||||
```css
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.ShowSchools {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
background: rgb(240, 240, 240);
|
||||
min-height: 515px;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 75%;
|
||||
min-width: 400px;
|
||||
min-height: 400px;
|
||||
|
||||
background: white;
|
||||
|
||||
/* Set height to a maximum of 100% or fit-content */
|
||||
height: min(100%, fit-content);
|
||||
|
||||
margin: 0 auto;
|
||||
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
```
|
||||
|
||||
Here if we use 100% as height then it will cause overflow as height wont increase beyond 100% of container and if we set height as fit-content then height will be 0 if no min-height is set and also it wont occupy the 100% as default
|
||||
|
||||
this method if not working then use wrapper like this
|
||||
|
||||
```css
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
// height: min(100%, fit-content);
|
||||
}
|
||||
|
||||
.ShowSchools {
|
||||
width: 100%;
|
||||
// height: 100vh;
|
||||
background: rgb(240, 240, 240);
|
||||
min-height: 515px;
|
||||
// height: max(100%, fit-content);
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.heading {
|
||||
padding: 1px;
|
||||
height: 100px;
|
||||
h1 {
|
||||
text-align: center;
|
||||
}
|
||||
// margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.container-wrapper {
|
||||
width: 75%;
|
||||
min-width: 400px;
|
||||
min-height: 400px;
|
||||
display: flex;
|
||||
// align-items: center;
|
||||
justify-content: center;
|
||||
// height: 100%;
|
||||
height: calc(100% - (100px + 16px + 1px + 2px));
|
||||
background: white;
|
||||
margin: 0 auto;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
// height: calc(100% - (100px + 16px + 1px + 2px));
|
||||
height: fit-content;
|
||||
// height: max(100%, fit-content);
|
||||
// height: calc(max(100% - (100px + 16px + 1px + 2px), fit-content));
|
||||
// height: max(calc(100vh - (100px + 16px + 1px + 2px)), fit-content);
|
||||
// overflow: auto;
|
||||
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
```
|
||||
46
joplin notion extension/Web Development/CSS/syncfusion.md
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
syncfusion
|
||||
for asp.net core
|
||||
https://ej2.syncfusion.com/aspnetcore/documentation/introduction
|
||||
|
||||
|
||||
Installation on linux
|
||||
https://www.baeldung.com/linux/asp-net-server
|
||||
|
||||
textbox
|
||||
https://ej2.syncfusion.com/aspnetcore/documentation/textbox/getting-started
|
||||
|
||||
grids
|
||||
|
||||
|
||||
|
||||
**asp.net core**
|
||||
in asp.net core in model class we cant have our own default constructor. reason can be that they have their own default constructors resulting in collision.
|
||||
- setup project
|
||||
`dotnet new webapp --output aspnetcoreapp --no-https`
|
||||
then
|
||||
`dotnet run`
|
||||
`dotnet watch run` for hot reloading
|
||||
|
||||
Adding syncfusion
|
||||
`dotnet add package Syncfusion.EJ2.AspNet.Core`
|
||||
then in `~/_ViewImports.cshtml`
|
||||
`@addTagHelper *, Syncfusion.EJ2`
|
||||
|
||||
in `~/_Layout.cshtml`
|
||||
```html
|
||||
|
||||
<head>
|
||||
...
|
||||
<!-- Syncfusion ASP.NET Core controls style -->
|
||||
<link rel="stylesheet" href="https://cdn.syncfusion.com/ej2/28.2.3/material.css" />
|
||||
<!-- Syncfusion ASP.NET Core controls script -->
|
||||
<script src="https://cdn.syncfusion.com/ej2/28.2.3/dist/ej2.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
...
|
||||
<!-- Syncfusion ASP.NET Core Script Manager -->
|
||||
<ejs-scripts></ejs-scripts>
|
||||
</body>
|
||||
```
|
||||
|
||||
5
joplin notion extension/Web Development/CSS/tailwind.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
tailwind
|
||||
|
||||
i mean we have to memorize its own classes and its basically a css just using in jsx/html instead of separate css files
|
||||
also if u have a css class named smooth-button and it contain like 12 properties then can simply use that same class for more buttons
|
||||
but in case of tailwind u have to write classes for 12 separate properties and whenever it is to be reused we need to write those 12 classes again
|
||||
14
joplin notion extension/Web Development/C_C++/Basics.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
Basics
|
||||
|
||||
- const char vs char
|
||||
`const char *p`: This declares a pointer p that points to a constant character (immutable). It means that the data pointed to by p cannot be modified through p. However, p itself can be changed to point to a different memory location.
|
||||
So `p[0]='H'` is invalid as this constant say 'hello' is read only
|
||||
but if it is simply `char *p` then `p[0]='H'` is a valid operation
|
||||
|
||||
**Wierd Case**
|
||||
if
|
||||
`const char *p` is equivalent to 'hello' and we do
|
||||
`char *q=p;`
|
||||
and
|
||||
`q[0]='H'`
|
||||
then it is invalid bcz constant pointed by p is still read only and no matter if another pointer is pointing to it, that constant is still read only.
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
C environment
|
||||
|
||||
### editor
|
||||
❌ vscode/codium, eclipse, atom, sublime text
|
||||
✅ vi(m), acme, sam, neovim to some point
|
||||
|
||||
### c compiler
|
||||
❌ gcc, clang
|
||||
✅ tcc, scc, 8c
|
||||
|
||||
### libc
|
||||
❌glibc
|
||||
✅ musl (only if on linux), uclibc, dietlibc
|
||||
|
||||
### build system
|
||||
❌ cmake, meson
|
||||
✅ make, mk
|
||||
|
||||
❌ systemd(ick)
|
||||
✅ sinit, runit, sysvinit, s6, openrc
|
||||
|
||||
windowing system
|
||||
❌ wayland
|
||||
➖ x11
|
||||
✅ rio
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
FLTK Classes and Functions
|
||||
|
||||
1. editor->show_insert_position(); editor is of class 'Fl_Text_Editor'
|
||||
this function can be useful, for example, when you programmatically move the insert position to a specific location within the text buffer, and you want to make sure that this position is visible to the user in the UI.
|
||||
26
joplin notion extension/Web Development/C_C++/FLTK/Logs.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
Logs
|
||||
|
||||
```
|
||||
=== installing FL ===
|
||||
make[1]: Entering directory '/home/hpm/Videos/imp/cpp/fltk/helloworld/fltk-1.3.9/FL'
|
||||
Installing include files in /usr/local/include...
|
||||
make[1]: Leaving directory '/home/hpm/Videos/imp/cpp/fltk/helloworld/fltk-1.3.9/FL'
|
||||
=== installing src ===
|
||||
make[1]: Entering directory '/home/hpm/Videos/imp/cpp/fltk/helloworld/fltk-1.3.9/src'
|
||||
Installing libraries in /usr/local/lib...
|
||||
make[1]: Leaving directory '/home/hpm/Videos/imp/cpp/fltk/helloworld/fltk-1.3.9/src'
|
||||
=== installing fluid ===
|
||||
make[1]: Entering directory '/home/hpm/Videos/imp/cpp/fltk/helloworld/fltk-1.3.9/fluid'
|
||||
Installing FLUID in /usr/local/bin...
|
||||
make[1]: Leaving directory '/home/hpm/Videos/imp/cpp/fltk/helloworld/fltk-1.3.9/fluid'
|
||||
=== installing test ===
|
||||
make[1]: Entering directory '/home/hpm/Videos/imp/cpp/fltk/helloworld/fltk-1.3.9/test'
|
||||
Installing example programs to /usr/local/share/doc/fltk/examples...
|
||||
make[1]: Leaving directory '/home/hpm/Videos/imp/cpp/fltk/helloworld/fltk-1.3.9/test'
|
||||
=== installing documentation ===
|
||||
make[1]: Entering directory '/home/hpm/Videos/imp/cpp/fltk/helloworld/fltk-1.3.9/documentation'
|
||||
Installing documentation files in /usr/local/share/doc/fltk ...
|
||||
Installing man pages in /usr/local/share/man ...
|
||||
make[1]: Leaving directory '/home/hpm/Videos/imp/cpp/fltk/helloworld/fltk-1.3.9/documentation'
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,430 @@
|
|||
Text_Editor
|
||||
|
||||
EditorWindow.h
|
||||
|
||||
```cpp
|
||||
#include <FL/Fl_Double_Window.H>
|
||||
|
||||
#include <FL/Fl_Button.H>
|
||||
#include <FL/Fl_Input.H>
|
||||
#include <FL/Fl_Return_Button.H>
|
||||
#include <FL/Fl_Text_Editor.H>
|
||||
#include <FL/Fl_Widget.H>
|
||||
|
||||
class EditorWindow : public Fl_Double_Window {
|
||||
public:
|
||||
EditorWindow(int w, int h, const char *t);
|
||||
~EditorWindow();
|
||||
|
||||
Fl_Window *replace_dlg;
|
||||
Fl_Input *replace_find;
|
||||
Fl_Input *replace_with;
|
||||
|
||||
Fl_Button *replace_all;
|
||||
Fl_Return_Button *replace_next;
|
||||
Fl_Button *replace_cancel;
|
||||
|
||||
Fl_Text_Editor *editor;
|
||||
char search[256];
|
||||
};
|
||||
|
||||
int check_save(void);
|
||||
void load_file(char *newfile, int ipos);
|
||||
void save_file(char *newfile);
|
||||
void set_title(Fl_Window *w);
|
||||
|
||||
void new_cb(Fl_Widget *, void *);
|
||||
void changed_cb(int, int nInserted, int nDeleted, int, const char *, void *v);
|
||||
void copy_cb(Fl_Widget *, void *v);
|
||||
void cut_cb(Fl_Widget *, void *v);
|
||||
void delete_cb(Fl_Widget *, void *v);
|
||||
void find_cb(Fl_Widget *w, void *v);
|
||||
void find2_cb(Fl_Widget *w, void *v);
|
||||
void new_cb(Fl_Widget *, void *);
|
||||
void open_cb(Fl_Widget *, void *);
|
||||
void paste_cb(Fl_Widget *, void *v);
|
||||
void quit_cb(Fl_Widget *, void *);
|
||||
void replace_cb(Fl_Widget *, void *v);
|
||||
void replace2_cb(Fl_Widget *, void *v);
|
||||
void replall_cb(Fl_Widget *, void *v);
|
||||
void replcan_cb(Fl_Widget *, void *v);
|
||||
void save_cb(void);
|
||||
void saveas_cb(void);
|
||||
```
|
||||
|
||||
helpers.cpp
|
||||
```cpp
|
||||
#include "EditorWindow.h"
|
||||
#include <FL/Fl_File_Chooser.H>
|
||||
#include <FL/Fl_Text_Editor.H>
|
||||
#include <FL/fl_ask.H>
|
||||
#include <cerrno>
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
|
||||
int changed = 0;
|
||||
|
||||
int loading = 0;
|
||||
char filename[256] = "";
|
||||
Fl_Text_Buffer *textbuf;
|
||||
|
||||
void changed_cb(int, int nInserted, int nDeleted, int, const char *, void *v) {
|
||||
if ((nInserted) || (nDeleted) && !loading)
|
||||
changed = 1;
|
||||
EditorWindow *w = (EditorWindow *)v;
|
||||
set_title(w);
|
||||
if (loading)
|
||||
w->editor->show_insert_position();
|
||||
}
|
||||
|
||||
void copy_cb(Fl_Widget *, void *v) {
|
||||
EditorWindow *e = (EditorWindow *)v;
|
||||
Fl_Text_Editor::kf_copy(0, e->editor);
|
||||
}
|
||||
|
||||
void cut_cb(Fl_Widget *, void *v) {
|
||||
EditorWindow *e = (EditorWindow *)v;
|
||||
Fl_Text_Editor::kf_cut(0, e->editor);
|
||||
}
|
||||
|
||||
void delete_cb(Fl_Widget *, void *v) { textbuf->remove_selection(); }
|
||||
|
||||
void find_cb(Fl_Widget *w, void *v) {
|
||||
EditorWindow *e = (EditorWindow *)v;
|
||||
const char *val;
|
||||
// val = e->replace_find->value();
|
||||
val = fl_input("Search String:", e->search);
|
||||
if (val != NULL) {
|
||||
strcpy(e->search, val);
|
||||
find2_cb(w, v);
|
||||
}
|
||||
}
|
||||
|
||||
void find2_cb(Fl_Widget *w, void *v) {
|
||||
EditorWindow *e = (EditorWindow *)v;
|
||||
if (e->search[0] == '\0') {
|
||||
find_cb(w, v);
|
||||
return;
|
||||
}
|
||||
|
||||
int pos = e->editor->insert_position();
|
||||
int found = textbuf->search_forward(pos, e->search, &pos);
|
||||
|
||||
if (found) {
|
||||
// found
|
||||
textbuf->select(pos, pos + strlen(e->search));
|
||||
e->editor->insert_position(pos + strlen(e->search));
|
||||
e->editor->show_insert_position();
|
||||
}
|
||||
|
||||
else {
|
||||
fl_alert("No occurrences of \'%s\' found!", e->search);
|
||||
std::cout << "No occureences of " << e->search << " found.";
|
||||
}
|
||||
}
|
||||
|
||||
void new_cb(Fl_Widget *, void *) {
|
||||
if (!check_save())
|
||||
return;
|
||||
filename[0] = '\0';
|
||||
textbuf->select(0, textbuf->length());
|
||||
textbuf->remove_selection();
|
||||
changed = 0;
|
||||
textbuf->call_modify_callbacks();
|
||||
}
|
||||
|
||||
void open_cb(Fl_Widget *, void *) {
|
||||
if (!check_save())
|
||||
return;
|
||||
char *newfile = fl_file_chooser("Open File?", "*", filename);
|
||||
if (newfile != NULL)
|
||||
load_file(newfile, -1);
|
||||
}
|
||||
|
||||
void paste_cb(Fl_Widget *, void *v) {
|
||||
EditorWindow *e = (EditorWindow *)v;
|
||||
Fl_Text_Editor::kf_paste(0, e->editor);
|
||||
}
|
||||
|
||||
void quit_cb(Fl_Widget *, void *) {
|
||||
if (changed && !check_save())
|
||||
return;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void replace_cb(Fl_Widget *, void *v) {
|
||||
EditorWindow *e = (EditorWindow *)v;
|
||||
e->replace_dlg->show();
|
||||
}
|
||||
|
||||
void replace2_cb(Fl_Widget *, void *v) {
|
||||
EditorWindow *e = (EditorWindow *)v;
|
||||
const char *find = e->replace_find->value();
|
||||
const char *replace = e->replace_with->value();
|
||||
|
||||
if (find[0] == '\0') {
|
||||
// search
|
||||
e->replace_dlg->show();
|
||||
return;
|
||||
}
|
||||
|
||||
e->replace_dlg->hide();
|
||||
|
||||
int pos = e->editor->insert_position();
|
||||
int found = textbuf->search_forward(pos, find, &pos);
|
||||
if (found) {
|
||||
// Found a match
|
||||
textbuf->select(pos, pos + strlen(find));
|
||||
textbuf->remove_selection();
|
||||
textbuf->insert(pos, replace);
|
||||
textbuf->select(pos, pos + strlen(replace));
|
||||
e->editor->insert_position(pos + strlen(replace));
|
||||
e->editor->show_insert_position();
|
||||
|
||||
} else {
|
||||
fl_alert("No occurrences of \'%s\' found!", find);
|
||||
}
|
||||
}
|
||||
|
||||
void replall_cb(Fl_Widget *, void *v) {
|
||||
EditorWindow *e = (EditorWindow *)v;
|
||||
const char *find = e->replace_find->value();
|
||||
const char *replace = e->replace_with->value();
|
||||
|
||||
if (find[0] == '\0') {
|
||||
// search
|
||||
e->replace_dlg->show();
|
||||
return;
|
||||
}
|
||||
|
||||
e->replace_dlg->hide();
|
||||
|
||||
e->editor->insert_position(0);
|
||||
int times = 0;
|
||||
|
||||
// loop through whole string
|
||||
// loop will end once found is 0 which means no more matches
|
||||
for (int found = 1; found;) {
|
||||
int pos = e->editor->insert_position();
|
||||
found = textbuf->search_forward(pos, find, &pos);
|
||||
if (found) {
|
||||
// Found a match
|
||||
textbuf->select(pos, pos + strlen(find));
|
||||
textbuf->remove_selection();
|
||||
textbuf->insert(pos, replace);
|
||||
textbuf->select(pos, pos + strlen(replace));
|
||||
e->editor->insert_position(pos + strlen(replace));
|
||||
e->editor->show_insert_position();
|
||||
times++;
|
||||
}
|
||||
}
|
||||
|
||||
if (times)
|
||||
fl_message("Replace %d occurrences.", times);
|
||||
else
|
||||
fl_alert("No occurrences of \'%s\' found!", find);
|
||||
}
|
||||
|
||||
void replcan_cb(Fl_Widget *, void *v) {
|
||||
EditorWindow *e = (EditorWindow *)v;
|
||||
e->replace_dlg->hide();
|
||||
}
|
||||
|
||||
void save_cb(void) {
|
||||
if (filename[0] == '\0') {
|
||||
// no filename so getting one
|
||||
saveas_cb();
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
else
|
||||
save_file(filename);
|
||||
}
|
||||
|
||||
void saveas_cb(void) {
|
||||
char *newfile;
|
||||
newfile = fl_file_chooser("Save File As?", "*", filename);
|
||||
if (newfile != NULL)
|
||||
save_file(newfile);
|
||||
}
|
||||
|
||||
// other functions-------------------
|
||||
|
||||
int check_save(void) {
|
||||
if (!changed)
|
||||
return 1;
|
||||
|
||||
int r = fl_choice(
|
||||
"The current file has not been saved.\nWould you like to save it now?",
|
||||
"Cancel", "Save", "Discard");
|
||||
|
||||
if (r == 1) {
|
||||
save_cb();
|
||||
return !changed;
|
||||
}
|
||||
|
||||
return (r == 2) ? 1 : 0;
|
||||
}
|
||||
|
||||
void load_file(char *newfile, int ipos) {
|
||||
loading = 1;
|
||||
int insert = (ipos != -1);
|
||||
changed = insert;
|
||||
if (!insert)
|
||||
strcpy(filename, "");
|
||||
int r;
|
||||
if (!insert)
|
||||
r = textbuf->loadfile(newfile);
|
||||
else
|
||||
r = textbuf->insertfile(newfile, ipos);
|
||||
if (r) {
|
||||
fl_alert("Error reading from file \'%s\':\n%s.", newfile, strerror(errno));
|
||||
} else if (!insert)
|
||||
strcpy(filename, newfile);
|
||||
loading = 0;
|
||||
textbuf->call_modify_callbacks();
|
||||
}
|
||||
|
||||
void save_file(char *newfile) {
|
||||
int saveResult = textbuf->savefile(newfile);
|
||||
if (saveResult) {
|
||||
fl_alert("Error writing to file \'%s\':\n%s.", newfile, strerror(errno));
|
||||
} else
|
||||
strcpy(filename, newfile);
|
||||
changed = 0;
|
||||
textbuf->call_modify_callbacks();
|
||||
}
|
||||
|
||||
void set_title(Fl_Window *w) {
|
||||
|
||||
char title[256];
|
||||
if (filename[0] == '\0')
|
||||
strcpy(title, "Untitled");
|
||||
else {
|
||||
char *slash;
|
||||
// /home/username/test.txt
|
||||
// so strrchr will return pointer pointing to last `/` so result will be
|
||||
// '/test/txt'.
|
||||
slash = strrchr(filename, '/');
|
||||
if (slash == NULL)
|
||||
slash = strrchr(filename, '\\');
|
||||
if (slash != NULL)
|
||||
// slash+1 to skip the included slash
|
||||
strcpy(title, slash + 1);
|
||||
else
|
||||
strcpy(title, filename);
|
||||
}
|
||||
|
||||
if (changed)
|
||||
strcat(title, " (modified)");
|
||||
w->label(title);
|
||||
}
|
||||
|
||||
// void save_cb() {
|
||||
// // Your implementation for save_cb
|
||||
// // For example:
|
||||
// std::cout << "Saving file...\n";
|
||||
// }
|
||||
//
|
||||
// void saveas_cb() {
|
||||
// // Your implementation for saveas_cb
|
||||
// // For example:
|
||||
// std::cout << "Saving file as...\n";
|
||||
/
|
||||
```
|
||||
|
||||
main.cpp
|
||||
```cpp
|
||||
|
||||
#include "helpers.cpp"
|
||||
#include <FL/Enumerations.H>
|
||||
#include <FL/Fl.H>
|
||||
#include <FL/Fl_Button.H>
|
||||
#include <FL/Fl_Image.H>
|
||||
#include <FL/Fl_Menu_Bar.H>
|
||||
#include <FL/Fl_Menu_Item.H>
|
||||
#include <FL/Fl_Return_Button.H>
|
||||
#include <FL/Fl_Text_Buffer.H>
|
||||
#include <FL/Fl_Text_Editor.H>
|
||||
#include <FL/Fl_Widget.H>
|
||||
#include <FL/Fl_Window.H>
|
||||
using namespace std;
|
||||
|
||||
// global variables to keep track of things
|
||||
|
||||
EditorWindow::EditorWindow(int w, int h, const char *t)
|
||||
: Fl_Double_Window(w, h, t) {
|
||||
Fl_Menu_Item menuItems1[] = {
|
||||
{"&File", 0, 0, 0, FL_SUBMENU},
|
||||
{"&New File", 0, (Fl_Callback *)new_cb},
|
||||
{"&Open File...", FL_COMMAND + 'o', (Fl_Callback *)open_cb},
|
||||
|
||||
{"&Save File", FL_COMMAND + 's', (Fl_Callback *)save_cb},
|
||||
{"Save File &As...", FL_COMMAND + FL_SHIFT + 's',
|
||||
(Fl_Callback *)saveas_cb, 0, FL_MENU_DIVIDER},
|
||||
|
||||
{"E&xit", FL_COMMAND + 'q', (Fl_Callback *)quit_cb, 0},
|
||||
{0},
|
||||
|
||||
{"&Edit", 0, 0, 0, FL_SUBMENU},
|
||||
|
||||
{"Cu&t", FL_COMMAND + 'x', (Fl_Callback *)cut_cb, this},
|
||||
{"&Copy", FL_COMMAND + 'c', (Fl_Callback *)copy_cb, this},
|
||||
{"&Paste", FL_COMMAND + 'v', (Fl_Callback *)paste_cb, this},
|
||||
{"&Delete", 0, (Fl_Callback *)delete_cb},
|
||||
{0},
|
||||
|
||||
{"&Search", 0, 0, 0, FL_SUBMENU},
|
||||
{"&Find...", FL_COMMAND + 'f', (Fl_Callback *)find_cb, this},
|
||||
{"F&ind Again", FL_COMMAND + 'g', find2_cb, this},
|
||||
{"&Replace...", FL_COMMAND + 'r', replace_cb, this},
|
||||
{"Re&place Again", FL_COMMAND + 't', replace2_cb, this},
|
||||
{0},
|
||||
|
||||
{0}};
|
||||
Fl_Menu_Bar *m = new Fl_Menu_Bar(0, 0, 600, 30);
|
||||
m->copy(menuItems1);
|
||||
|
||||
editor = new Fl_Text_Editor(0, 30, 640, 370);
|
||||
editor->buffer(textbuf);
|
||||
|
||||
textbuf->add_modify_callback(changed_cb, this);
|
||||
textbuf->call_modify_callbacks();
|
||||
|
||||
editor->textfont(FL_COURIER);
|
||||
|
||||
replace_dlg = new Fl_Window(300, 105, "Replace");
|
||||
replace_find = new Fl_Input(70, 10, 200, 25, "Find:");
|
||||
replace_with = new Fl_Input(70, 40, 200, 25, "Replace:");
|
||||
replace_all = new Fl_Button(10, 70, 90, 25, "Replace All");
|
||||
replace_next = new Fl_Return_Button(105, 70, 120, 25, "Replace Next");
|
||||
replace_cancel = new Fl_Button(230, 70, 60, 25, "Cancel");
|
||||
|
||||
replace_all->callback(replall_cb, this);
|
||||
replace_next->callback(replace2_cb, this);
|
||||
replace_cancel->callback(replcan_cb, this);
|
||||
}
|
||||
|
||||
EditorWindow::~EditorWindow() {
|
||||
// something
|
||||
int a = 2;
|
||||
}
|
||||
|
||||
// EditorWindow *w = new EditorWindow(720, 500);
|
||||
// w->editor = new Fl_Text_Editor(0, 30, 640, 370);
|
||||
// w->editor->buffer(textbuf);
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
textbuf = new Fl_Text_Buffer;
|
||||
|
||||
EditorWindow *window = new EditorWindow(700, 500, "Window1");
|
||||
|
||||
window->show(argc, argv);
|
||||
|
||||
return Fl::run();
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
advanced text editor
|
||||
https://codeberg.org/sharecodeless/fltk_text_editor
|
||||
|
||||
EditorWindow.h
|
||||
```cpp
|
||||
|
||||
```
|
||||
70
joplin notion extension/Web Development/C_C++/FLTK/code.md
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
code
|
||||
|
||||
```cpp
|
||||
#include <FL/Fl.H>
|
||||
#include <FL/Fl_Box.H>
|
||||
#include <FL/Fl_Window.H>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
Fl_Window *window = new Fl_Window(300, 180);
|
||||
Fl_Box *box = new Fl_Box(20, 40, 260, 100, "Hello, World!");
|
||||
box->box(FL_UP_BOX);
|
||||
box->labelsize(36);
|
||||
box->labelfont(FL_BOLD + FL_ITALIC);
|
||||
box->labeltype(FL_SHADOW_LABEL);
|
||||
window->end();
|
||||
window->show(argc, argv);
|
||||
return Fl::run();
|
||||
}
|
||||
```
|
||||

|
||||
|
||||
more random
|
||||
```cpp
|
||||
#include <FL/Fl_Return_Button.H>
|
||||
#include <FL/Fl_Window.H>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
Fl_Window *window = new Fl_Window(300, 180);
|
||||
Fl_Box *box = new Fl_Box(20, 40, 30, 20, "Hello!");
|
||||
box->box(FL_UP_BOX);
|
||||
box->labelsize(9);
|
||||
box->labelfont(FL_BOLD + FL_ITALIC);
|
||||
Fl_Return_Button *retBtn = new Fl_Return_Button(70, 80, 50, 30, "Button1");
|
||||
retBtn->type(FL_NORMAL_BUTTON);
|
||||
retBtn->labelsize(10);
|
||||
|
||||
box->labeltype(FL_EMBOSSED_LABEL);
|
||||
window->end();
|
||||
window->show(argc, argv);
|
||||
return Fl::run();
|
||||
}
|
||||
```
|
||||

|
||||
|
||||
- To run bash script in C
|
||||
```cpp
|
||||
#include <cstdlib> // For the system function
|
||||
|
||||
int main() {
|
||||
// Replace "your_script.sh" with the actual path to your bash script
|
||||
const char* scriptPath = "your_script.sh";
|
||||
|
||||
// Run the bash script using the system function
|
||||
int result = system(scriptPath);
|
||||
|
||||
// Check the result of the system call
|
||||
if (result == 0) {
|
||||
// The script was executed successfully
|
||||
// Add your FLTK code or other logic here
|
||||
} else {
|
||||
// There was an error executing the script
|
||||
// Handle the error or display a message
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
commits
|
||||
|
||||
commit b79b079322ee327069cf24c6b2fbb1cdb996c678 (HEAD -> master)
|
||||
Author: Your Name <you@example.com>
|
||||
Date: Tue Jan 30 22:05:08 2024 +0530
|
||||
|
||||
all is complete
|
||||
|
||||
|
||||
commit 0cfa890aaaa86880d530c08ab637787146577f6d (HEAD -> master)
|
||||
Author: Your Name <you@example.com>
|
||||
Date: Tue Jan 30 22:35:58 2024 +0530
|
||||
|
||||
constructor one
|
||||
|
||||
|
||||
commit e505df85c2258eced25905200b1e2ac29c2bb876 (HEAD -> master)
|
||||
Author: Your Name <you@example.com>
|
||||
Date: Wed Jan 31 00:29:22 2024 +0530
|
||||
|
||||
finally complete
|
||||
|
||||
commit 683f6bcbf3ff527d0b255cb21f20dda8b806d864 (HEAD -> master)
|
||||
Author: Your Name <you@example.com>
|
||||
Date: Wed Jan 31 14:33:04 2024 +0530
|
||||
|
||||
before cross checking
|
||||
|
||||
commit ffe10dcc082fa0fd32051ea0131e63a8df6858b5 (HEAD -> master)
|
||||
Author: Your Name <you@example.com>
|
||||
Date: Wed Jan 31 15:53:26 2024 +0530
|
||||
|
||||
before replacing whole file
|
||||
34
joplin notion extension/Web Development/C_C++/FLTK/fltk.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
Fltk
|
||||
https://www.fltk.org/
|
||||
https://www.youtube.com/watch?v=6W3o8UGW2aM
|
||||
Initialization
|
||||
|
||||
- Running without Installation
|
||||
https://www.youtube.com/watch?v=6W3o8UGW2aM
|
||||
first download source tar.gz from their official website download section https://www.fltk.org/software.php
|
||||
https://www.mediafire.com/file/pyfosfvge4did2p/fltk-1.3.9-source.tar.gz/file
|
||||
fltk-1.3.9-source.tar.gz https://files.catbox.moe/grylch.gz
|
||||
|
||||
Create a project folder and extract
|
||||
Then extract that zip file in `project_folder/fltp-xxx/`
|
||||
go to that directory and compile using make. `make`. Now go back to project root
|
||||
Linking header path and lib path:
|
||||
Libraries of x11 are found in `/usr/lib/x86_64-linux-gnu` or `/usr/lib`
|
||||
`g++ main.cpp -Ifltk-1.3.9 -Lfltk-1.3.9/lib -lfltk -lX11 -lXfixes -lXext -lXft -lXrender -lfontconfig -lXcursor -lXinerama -ldl -o main`
|
||||
Here `-I` represents header file path
|
||||
`-L` represents library path
|
||||
`-l` represents library files `-lfltk` means file named `libfltk.a`
|
||||
|
||||
- Running with installation
|
||||
https://www.youtube.com/watch?v=yHx1h25cyvc
|
||||
After using `make` and before going back to project root. use `sudo make install` to install the compiled fltk binary.
|
||||
In project root
|
||||
`fltk-config --use-images --compile main.cpp`
|
||||
For debugging information like `--debug` in gcc and g++ do this(adding `-g`)
|
||||
`fltk-config --use-images --compile main.cpp -g`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
139
joplin notion extension/Web Development/C_C++/File Handling.md
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
File Handling
|
||||
|
||||
- To open a file
|
||||
```c
|
||||
FILE *file_pointer;
|
||||
file_pointer = fopen("filename.txt", "mode");
|
||||
|
||||
|
||||
```
|
||||
"mode" specifies the purpose for opening the file, such as "r" for reading, "w" for writing, "a" for appending, "r+" for reading and writing, "w+" for reading and writing, truncating the file, etc.
|
||||
- Checking if File Opened Successfully
|
||||
```c
|
||||
if (file_pointer == NULL) {
|
||||
// File opening failed
|
||||
// Handle the error
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- Reading from a File
|
||||
```c
|
||||
// Reading using fscanf
|
||||
int num;
|
||||
fscanf(file_pointer, "%d", &num);
|
||||
|
||||
// Reading using fgets
|
||||
char buffer[255];
|
||||
fgets(buffer, 255, file_pointer);
|
||||
```
|
||||
fscanf will read just word
|
||||
fgets will read whole line
|
||||
|
||||
- Writing to a File
|
||||
|
||||
Use fprintf() or fputs() to write data to the file:
|
||||
```c
|
||||
// Writing using fprintf
|
||||
fprintf(file_pointer, "Hello, File!");
|
||||
|
||||
// Writing using fputs
|
||||
fputs("Hello, File!", file_pointer);
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
- Closing a File
|
||||
|
||||
Always close the file after performing operations:
|
||||
```c
|
||||
fclose(file_pointer);
|
||||
```
|
||||
|
||||
|
||||
- Reading file Line by Line
|
||||
```c
|
||||
#define BUFFER_SIZE 1024 // Define a reasonable buffer size
|
||||
|
||||
FILE *file_pointer;
|
||||
file_pointer = fopen("filename.txt", "r");
|
||||
|
||||
if (file_pointer == NULL) {
|
||||
printf("File could not be opened.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
char buffer[BUFFER_SIZE];
|
||||
|
||||
while (fgets(buffer, BUFFER_SIZE, file_pointer) != NULL) {
|
||||
// Remove the newline character, if present
|
||||
size_t length = strlen(buffer);
|
||||
if (length > 0 && buffer[length - 1] == '\n') {
|
||||
buffer[length - 1] = '\0'; // Replace '\n' with '\0' (null terminator)
|
||||
}
|
||||
// Process the line read from the file in 'buffer'
|
||||
printf("%s", buffer); // Print the line (or perform operations as needed)
|
||||
}
|
||||
|
||||
fclose(file_pointer);
|
||||
```
|
||||
|
||||
- When not sure about length of lines
|
||||
1. Dynamic Memory Allocation:
|
||||
|
||||
You can dynamically allocate memory for each line by using functions like malloc() to adjust the buffer size according to the length of the read line. This method allows flexibility but requires careful memory management and error handling.
|
||||
```c
|
||||
FILE *file_pointer;
|
||||
file_pointer = fopen("filename.txt", "r");
|
||||
|
||||
if (file_pointer == NULL) {
|
||||
printf("File could not be opened.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
char *buffer = NULL;
|
||||
size_t buffer_size = 0;
|
||||
|
||||
while (getline(&buffer, &buffer_size, file_pointer) != -1) {
|
||||
// Process the line read from the file in 'buffer'
|
||||
printf("%s", buffer); // Print the line (or perform operations as needed)
|
||||
}
|
||||
|
||||
free(buffer); // Free dynamically allocated memory
|
||||
fclose(file_pointer);
|
||||
```
|
||||
|
||||
|
||||
|
||||
2. Reading Characters One by One:
|
||||
Another approach is reading characters one by one until a newline ('\n') or the end of the file is encountered. This method gives you more control over memory but may involve more code and potentially be less efficient.
|
||||
```c
|
||||
FILE *file_pointer;
|
||||
file_pointer = fopen("filename.txt", "r");
|
||||
|
||||
if (file_pointer == NULL) {
|
||||
printf("File could not be opened.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int current_char;
|
||||
char buffer[MAX_LINE_LENGTH]; // Define a maximum line length
|
||||
|
||||
while ((current_char = fgetc(file_pointer)) != EOF) {
|
||||
if (current_char == '\n' || current_char == EOF) {
|
||||
// Process the line read from the file in 'buffer'
|
||||
printf("%s\n", buffer); // Print the line (or perform operations as needed)
|
||||
memset(buffer, 0, sizeof(buffer)); // Clear buffer for the next line
|
||||
} else {
|
||||
// Append character to buffer
|
||||
// Ensure buffer is not full to avoid overflow
|
||||
// Handle buffer overflow scenario
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file_pointer);
|
||||
```
|
||||
These are basic examples to illustrate the concept. The first method using getline() might be more convenient, while the second method gives you finer control over memory but involves more intricate handling. Adjust these examples according to your specific requirements and error handling needs.
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
Functions
|
||||
https://docs.gtk.org/gtk3/class.Window.html
|
||||
|
||||
|
||||
- https://docs.gtk.org/gtk3/enum.WindowPosition.html : GTK window position
|
||||
|
||||
|
||||
```c
|
||||
#include <gtk/gtk.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void gtk_main_quit1()
|
||||
{
|
||||
gtk_main_quit();
|
||||
// printf("Inside quit");
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc,char **argv)
|
||||
{
|
||||
// printf("hello world 12");
|
||||
|
||||
gtk_init(&argc,&argv);
|
||||
int a=12;
|
||||
int b=13;
|
||||
|
||||
const char *title;
|
||||
int width,height;
|
||||
|
||||
GtkWidget *window;
|
||||
// gtk_window_new(type) here type can be pop window or top level
|
||||
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
|
||||
|
||||
//to give title
|
||||
gtk_window_set_title(GTK_WINDOW(window),"firstapp");
|
||||
|
||||
// para: gtkwindow,width,height
|
||||
gtk_window_set_default_size(GTK_WINDOW(window), 500,500);
|
||||
|
||||
// type casting to GTK window as it is GTKWidget, and passing GtkWindowPosition as GTK_WIN_POS_CENTER_ALWAYS
|
||||
gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER_ALWAYS);
|
||||
|
||||
// if set to false user cant resize window
|
||||
gtk_window_set_resizable(GTK_WINDOW(window),TRUE);
|
||||
|
||||
// to remove title bar means no minimize,maximize or close btton and no title by setting to false
|
||||
gtk_window_set_decorated(GTK_WINDOW(window),TRUE);
|
||||
|
||||
// to maximize the window by default
|
||||
// gtk_window_maximize(GTK_WINDOW(window));
|
||||
|
||||
// getting title of window
|
||||
title=gtk_window_get_title(GTK_WINDOW(window));
|
||||
printf("Your title is: %s\n", title);
|
||||
|
||||
|
||||
|
||||
//getting size of window
|
||||
gtk_window_get_size(GTK_WINDOW(window),&width,&height);
|
||||
printf(" Width:%d\tHeight %d\n", width,height);
|
||||
|
||||
// checking if window is decorated or maximized or active
|
||||
printf("GTK WINDOW Decorated? %d\n", gtk_window_get_decorated(GTK_WINDOW(window) ));
|
||||
printf("GTK WINDOW Maximized? %d\n", gtk_window_is_maximized(GTK_WINDOW(window) ));
|
||||
printf("GTK WINDOW Active? %d\n", gtk_window_is_active(GTK_WINDOW(window) ));
|
||||
|
||||
|
||||
// callback function
|
||||
// 1st para is instance,2nd is detail,3rd is callback function handler, 4th is data to be passed to call back function
|
||||
// gtk_main_quit will quit the gtk_main program
|
||||
g_signal_connect(window,"destroy",G_CALLBACK(gtk_main_quit1),NULL);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// show all gtk widgets that are created. window is parent widget
|
||||
gtk_widget_show_all(window);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
gtk_main();
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
61
joplin notion extension/Web Development/C_C++/GTK/GTK Box.md
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
GTK Box
|
||||
https://devdocs.io/gtk~3.20/
|
||||
|
||||
Multiple widgets can be added in GTK Box unlike containers.
|
||||
|
||||
```c
|
||||
|
||||
//#include "gtk/gtksignal.h"
|
||||
#include <gtk/gtk.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
gtk_init(&argc,&argv);
|
||||
GtkWidget *window;
|
||||
|
||||
GtkWidget *box;
|
||||
|
||||
GtkWidget *button1;
|
||||
GtkWidget *button2;
|
||||
|
||||
|
||||
window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
|
||||
box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
|
||||
|
||||
|
||||
gtk_window_set_default_size(GTK_WINDOW(window), 500, 500);
|
||||
|
||||
button1= gtk_button_new_with_label("button1");
|
||||
// to initialize size(width and height) of gtk widget
|
||||
// Also this is the minimum size too
|
||||
gtk_widget_set_size_request(GTK_WIDGET(button1), 300, 300);
|
||||
button2= gtk_button_new_with_label("button2");
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(window), box);
|
||||
|
||||
// 1st para : box,2nd: child, 3rd: isexpand, 4th : isFill, 5th: padding
|
||||
gtk_box_pack_end(GTK_BOX(box), button1, TRUE,TRUE, 50);
|
||||
gtk_box_pack_start(GTK_BOX(box), button2, TRUE,TRUE, 50);
|
||||
// homogeneous box means all child widgets inside it are of same size
|
||||
int isHomo=gtk_box_get_homogeneous(GTK_BOX(box));
|
||||
printf("is Homogenous? %d\n",isHomo);
|
||||
|
||||
gtk_box_set_homogeneous(GTK_BOX(box),TRUE);
|
||||
|
||||
isHomo=gtk_box_get_homogeneous(GTK_BOX(box));
|
||||
printf("is Homogenous after setter call? %d\n",isHomo);
|
||||
|
||||
|
||||
|
||||
// gtk_container_remove(GTK_CONTAINER(window), button1);
|
||||
// gtk_container_add(GTK_CONTAINER(window), button2);
|
||||
|
||||
g_signal_connect(GTK_WINDOW(window),"destroy",G_CALLBACK(gtk_main_quit),NULL);
|
||||
gtk_widget_show_all(window);
|
||||
gtk_main();
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,50 @@
|
|||
GTK Fixed
|
||||
|
||||
Same as box, with difference ie in box size of widget depends on window but here in fixed size is fixed.
|
||||
|
||||
```c
|
||||
#include <gtk/gtk.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
gtk_init(&argc, &argv);
|
||||
int b = 13;
|
||||
int a = 10;
|
||||
printf("hey");
|
||||
|
||||
GtkWidget *window;
|
||||
GtkWidget *fixed;
|
||||
|
||||
GtkWidget *button1;
|
||||
GtkWidget *button2;
|
||||
|
||||
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
|
||||
gtk_window_set_default_size(GTK_WINDOW(window), 300, 200);
|
||||
|
||||
fixed = gtk_fixed_new();
|
||||
|
||||
button1 = gtk_button_new_with_label("button1");
|
||||
button2 = gtk_button_new_with_label("button2");
|
||||
|
||||
// para: fixed widget,widget inside it, xCor,yCor
|
||||
gtk_fixed_put(GTK_FIXED(fixed), button1, 100, 50);
|
||||
gtk_fixed_put(GTK_FIXED(fixed), button2, 200, 100);
|
||||
|
||||
// para: same with gtk_fixed_put but instead of adding widget it changes
|
||||
// coordinates
|
||||
gtk_fixed_move(GTK_FIXED(fixed), button1, 200, 100);
|
||||
gtk_fixed_move(GTK_FIXED(fixed), button2, 100, 50);
|
||||
|
||||
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(window), fixed);
|
||||
|
||||
gtk_widget_show_all(window);
|
||||
|
||||
gtk_main();
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
GTK container
|
||||
|
||||
- In GTK container only one widget is added at a time
|
||||
|
||||
Code
|
||||
|
||||
```c
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
gtk_init(&argc,&argv);
|
||||
GtkWidget *window;
|
||||
GtkWidget *button1;
|
||||
GtkWidget *button2;
|
||||
|
||||
|
||||
window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
|
||||
gtk_window_set_default_size(GTK_WINDOW(window), 500, 500);
|
||||
|
||||
button1= gtk_button_new_with_label("button1");
|
||||
button2= gtk_button_new_with_label("button2");
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(window), button1);
|
||||
gtk_container_remove(GTK_CONTAINER(window), button1);
|
||||
gtk_container_add(GTK_CONTAINER(window), button2);
|
||||
|
||||
g_signal_connect(GTK_WINDOW(window),"destroy",G_CALLBACK(gtk_main_quit),NULL);
|
||||
gtk_widget_show_all(window);
|
||||
gtk_main();
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
GTK with CSS
|
||||
|
||||
```c
|
||||
#include <gtk/gtk.h>
|
||||
#include <stdio.h>
|
||||
|
||||
static void load_css() {
|
||||
|
||||
const gchar *css_style_file = "style.css";
|
||||
GFile *css_fp = g_file_new_for_path(css_style_file);
|
||||
GError *error = 0;
|
||||
|
||||
GtkCssProvider *provider;
|
||||
// GtkStyleContext *context;
|
||||
GdkDisplay *display;
|
||||
GdkScreen *screen;
|
||||
|
||||
provider = gtk_css_provider_new();
|
||||
display = gdk_display_get_default();
|
||||
screen = gdk_display_get_default_screen(display);
|
||||
// context = gtk_widget_get_style_context(widget);
|
||||
|
||||
gtk_style_context_add_provider_for_screen(
|
||||
screen, GTK_STYLE_PROVIDER(provider),
|
||||
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
|
||||
gtk_css_provider_load_from_file(provider, css_fp, &error);
|
||||
|
||||
g_object_unref(provider);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
gtk_init(&argc, &argv);
|
||||
|
||||
GtkWidget *widgets[10];
|
||||
int n = 0;
|
||||
|
||||
GtkWidget *window;
|
||||
GtkWidget *button;
|
||||
|
||||
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
|
||||
load_css();
|
||||
|
||||
// GtkWidget *view;
|
||||
// GtkTextBuffer *buffer;
|
||||
|
||||
// GtkCssProvider *provider;
|
||||
// GtkStyleContext *context;
|
||||
|
||||
// view = gtk_text_view_new();
|
||||
|
||||
// buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
|
||||
|
||||
// gtk_text_buffer_set_text(buffer, "hello, some text", -1);
|
||||
|
||||
// provider = gtk_css_provider_new();
|
||||
|
||||
// gtk_css_provider_load_from_data(provider,
|
||||
// "textview { font : 15 serif; "
|
||||
// "background-color: blue; margin: 10px; "
|
||||
// "text-decoration-line : underline;}",
|
||||
// -1, NULL);
|
||||
|
||||
// context = gtk_widget_get_style_context(view);
|
||||
|
||||
// gtk_style_context_add_provider(context, GTK_STYLE_PROVIDER(provider),
|
||||
// GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
|
||||
|
||||
// gtk_text_view_set_left_margin(GTK_TEXT_VIEW(view), 30);
|
||||
button = gtk_button_new_with_label("click_me");
|
||||
|
||||
// to set id of element
|
||||
gtk_widget_set_name(button, "btn");
|
||||
|
||||
// to add class to element
|
||||
gtk_style_context_add_class(gtk_widget_get_style_context(button), "circular");
|
||||
|
||||
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(window), button);
|
||||
|
||||
g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);
|
||||
gtk_widget_show_all(window);
|
||||
|
||||
gtk_main();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
```
|
||||
|
||||
style.css
|
||||
```css
|
||||
window{
|
||||
background-color: yellow;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: green;
|
||||
border: 10px solid #000;
|
||||
|
||||
}
|
||||
|
||||
#btn{
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.circular{
|
||||
border-radius : 100%;
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
Installation
|
||||
|
||||
- `pacman -S gtk3`
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
MakeFile
|
||||
|
||||
```makefile
|
||||
# default target name: sourceFile of gtk
|
||||
# compilation command
|
||||
|
||||
# target: prequisites
|
||||
# action
|
||||
|
||||
mygtkapp: mainGTKapp.c
|
||||
gcc `pkg-config --cflags gtk+-3.0` -o main mainGTKapp.c `pkg-config --libs gtk+-3.0`
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
For making it more readable macros will be used
|
||||
|
||||
```MakeFile
|
||||
# macros
|
||||
PROG = main
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = `pkg-config --cflags gtk+-3.0`
|
||||
LIBS= `pkg-config --libs gtk+-3.0`
|
||||
|
||||
|
||||
|
||||
# default target name: sourceFile of gtk
|
||||
# compilation command
|
||||
|
||||
# target: prequisites
|
||||
# action
|
||||
|
||||
# mygtkapp: mainGTKapp.c
|
||||
# gcc `pkg-config --cflags gtk+-3.0` -o main mainGTKapp.c `pkg-config --libs gtk+-3.0`
|
||||
|
||||
|
||||
${PROG}: ${PROG}.c
|
||||
${CC} ${CFLAGS} -o ${PROG} ${PROG}.c ${LIBS}
|
||||
|
||||
# Make another argument clean
|
||||
clean:
|
||||
rm ${PROG}
|
||||
|
||||
|
||||
```
|
||||
|
||||
Use `make` to create the executable file and use `make clean` to remove executable
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
Other native desktop development alternatives
|
||||
|
||||
1. React native desktop
|
||||
2. React nodeGUI : 45 mb appimage size, 30mb RAM
|
||||
3. Qt
|
||||
4. Flutter
|
||||
5. ImGUI : https://github.com/ocornut/imgui
|
||||
6. There are, however, various experimental forks of React Native for desktop platforms such as `react-native-windows` for Univeral Windows Platform, `react-native-macos` for Mac and `react-native-desktop` for Linux. They're not developed by the main RN team, though, so your milage may vary.
|
||||
https://github.com/status-im/react-native-desktop-qt
|
||||
7. proton-native
|
||||
8. https://flet.dev/docs/ : 20 mb appimage size, 170mb in RAM
|
||||
9. Kivy : multitouch feature(more suited for mobile)
|
||||
10. PyGui(libraries in c++ for performance)
|
||||
11. Tkinter
|
||||
12. FLTK (Fast, Light Toolkit): in C++(small executable sizes)
|
||||
13. Toga : in python , native
|
||||
14. WxWidget c++,python
|
||||
16. JUCE (Jules' Utility Class Extensions):
|
||||
Languages: C++
|
||||
Description: JUCE is a comprehensive C++ framework for developing cross-platform audio, graphics, and GUI applications. It supports Windows, macOS, Linux, iOS, and Android.
|
||||
16. https://github.com/vurtun/nuklear : in C
|
||||
104
joplin notion extension/Web Development/C_C++/GTK/code.md
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
code
|
||||
https://docs.gtk.org/gtk3
|
||||
|
||||
Template
|
||||
|
||||
**main method way**
|
||||
```c
|
||||
#include <gtk/gtk.h>
|
||||
#include <stdio.h>
|
||||
|
||||
void gtk_main_quit1()
|
||||
{
|
||||
gtk_main_quit();
|
||||
printf("Inside quit");
|
||||
}
|
||||
|
||||
int main(int argc,char **argv)
|
||||
{
|
||||
printf("hello world 12");
|
||||
|
||||
gtk_init(&argc,&argv);
|
||||
int a=12;
|
||||
int b=13;
|
||||
|
||||
GtkWidget *window;
|
||||
|
||||
// gtk_window_new(type) here type can be pop window or top level
|
||||
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
||||
|
||||
// callback function
|
||||
// 1st para is instance,2nd is detail,3rd is callback function handler, 4th is data to be passed to call back function
|
||||
// gtk_main_quit will quit the gtk_main program
|
||||
g_signal_connect(window,"destroy",G_CALLBACK(gtk_main_quit1),NULL);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// show all gtk widgets that are created. window is parent widget
|
||||
gtk_widget_show_all(window);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
gtk_main();
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
Compile it with
|
||||
```bash
|
||||
gcc `pkg-config --cflags gtk+-3.0` -o main1 main.c `pkg-config --libs gtk+-3.0`
|
||||
```
|
||||
|
||||
Run it with `./main1`
|
||||
|
||||
|
||||
Better without infinite loop(**gtk application way**)
|
||||
|
||||
```c
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
static void activate(GtkApplication *app,gpointer user_data)
|
||||
{
|
||||
// gtk code comes here
|
||||
GtkWidget *window;
|
||||
|
||||
window= gtk_application_window_new(app);
|
||||
|
||||
gtk_widget_show_all(window);
|
||||
}
|
||||
|
||||
int main(int argc,char **argv)
|
||||
{
|
||||
|
||||
GtkApplication *app;
|
||||
int ret;
|
||||
int as=12;
|
||||
|
||||
// 1st para ie application name should have atleast one dot(.) character
|
||||
app= gtk_application_new("in.firstApp23",G_APPLICATION_FLAGS_NONE); // G_APPLICATION_FLAGS_NONE is enum whose value is 0
|
||||
// app= gtk_application_new("firstApp",G_APPLICATION_DEFAULT_FLAGS);
|
||||
g_signal_connect(app,"activate",G_CALLBACK(activate),NULL);
|
||||
ret=g_application_run(G_APPLICATION(app),argc,argv);
|
||||
|
||||
g_object_unref(app);
|
||||
|
||||
return ret;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
here `app` argument in `g_application_run` have to be type casted using `G_APPLICATION(app)` and `activate` function in gtk_application_new too have to be type casted using `G_CALLBACK(activate)`
|
||||
|
||||
31
joplin notion extension/Web Development/C_C++/QT/Setup.md
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
Setup
|
||||
- To be able to get suggesstion on qt based methods, classes. adding includepath is necessary. it is `/usr/include/qt` and `/usr/include/qt/QtWidgets`
|
||||
- for nvim and zed add `.clangd` in project directory and add following
|
||||
```yaml
|
||||
CompileFlags:
|
||||
Add:
|
||||
- "-I/usr/include/qt"
|
||||
- "-I/usr/include/qt/QtWidgets"
|
||||
|
||||
```
|
||||
in vscode its `.vscode/c_cpp_properties.json` under includepath
|
||||
```json
|
||||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Linux",
|
||||
"includePath": [
|
||||
"${workspaceFolder}/**",
|
||||
"/usr/include/qt/QtWidgets",
|
||||
"/usr/include/qt"
|
||||
],
|
||||
"defines": [],
|
||||
"compilerPath": "/usr/bin/clang",
|
||||
"cStandard": "c17",
|
||||
"cppStandard": "c++17",
|
||||
"intelliSenseMode": "linux-clang-x64"
|
||||
}
|
||||
],
|
||||
"version": 4
|
||||
}
|
||||
```
|
||||
52
joplin notion extension/Web Development/C_C++/Snippets.md
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
Snippets
|
||||
|
||||
- Including bash scrips
|
||||
```cpp
|
||||
#include <cstdlib> // For the system function
|
||||
|
||||
int main() {
|
||||
// Replace "your_script.sh" with the actual path to your bash script
|
||||
const char* scriptPath = "your_script.sh";
|
||||
|
||||
// Run the bash script using the system function
|
||||
int result = system(scriptPath);
|
||||
|
||||
// Check the result of the system call
|
||||
if (result == 0) {
|
||||
// The script was executed successfully
|
||||
// Add your FLTK code or other logic here
|
||||
} else {
|
||||
// There was an error executing the script
|
||||
// Handle the error or display a message
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
- Replacing first set of characters with a particular character(memset)
|
||||
Description : The C library function void \*memset(void \*str, int c, size_t n) copies the character c (an unsigned char) to the first n characters of the string pointed to, by the argument str.
|
||||
Application : Can be used to set all array to 0
|
||||
```c
|
||||
|
||||
// Program to replace first 7 bytes with $ symbol
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
int main () {
|
||||
char str[50];
|
||||
|
||||
strcpy(str,"This is string.h library function");
|
||||
puts(str);
|
||||
|
||||
memset(str,'$',7);
|
||||
puts(str);
|
||||
|
||||
return(0);
|
||||
}
|
||||
```
|
||||
Output
|
||||
```text
|
||||
This is string.h library function
|
||||
$$$$$$$ string.h library function
|
||||
```
|
||||
13
joplin notion extension/Web Development/C_C++/Syntax.md
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
Syntax
|
||||
|
||||
- template
|
||||
```cpp
|
||||
template <typename T>
|
||||
T add(T a, T b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
add<float>(5.f, 1.5f);
|
||||
add<int>(1, 2);
|
||||
add(20, 40); // Automatically deduces int
|
||||
```
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
GUI vs CLI
|
||||
|
||||
- CLI disadvantage
|
||||
In cli editor there is no proper autocomplete
|
||||
Also u can't use know what are the available methods for the object or description of specific object or function because that's GUI feature
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
VS Code
|
||||
|
||||
to download vs code extensions (vsix file) from marketplace site
|
||||
convert to following url
|
||||
`https://{PublisherName}.gallery.vsassets.io/_apis/public/gallery/publisher/{PublisherName}/extension/{ExtensionName}/latest/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage`
|
||||
|
||||
|
||||
- Phind ai in vs code
|
||||
- snippet by devon ray
|
||||
extension id : devonray.snippet
|
||||
- https://github.com/mhutchie/vscode-git-graph
|
||||
[git-graph-1.31.0-beta.3.vsix](../../../_resources/git-graph-1.31.0-beta.3.vsix)
|
||||
|
||||
- https://marketplace.visualstudio.com/items?itemName=EdwinSulaiman.jetbrains-rider-dark-theme : nice dark theme
|
||||
|
||||
[aaron-bond.better-comments-3.0.2.zip](../../../_resources/aaron-bond.better-comments-3.0.2.zip)
|
||||
|
||||
|
||||
|
||||
[aaronpowell.vscode-profile-switcher-0.4.0.zip](../../../_resources/aaronpowell.vscode-profile-switcher-0.4.0.zip)
|
||||
|
||||
|
||||
|
||||
[chakrounanas.turbo-console-log-2.5.6.zip](../../../_resources/chakrounanas.turbo-console-log-2.5.6.zip)
|
||||
|
||||
|
||||
[dsznajder.es7-react-js-snippets-4.4.3.zip](../../../_resources/dsznajder.es7-react-js-snippets-4.4.3.zip)
|
||||
|
||||
|
||||
|
||||
[esbenp.prettier-vscode-9.9.0.7z](../../../_resources/esbenp.prettier-vscode-9.9.0.7z)
|
||||
|
||||
|
||||
|
||||
|
||||
[jprestidge.theme-material-theme-1.0.1.7z](../../../_resources/jprestidge.theme-material-theme-1.0.1.7z)
|
||||
|
||||
|
||||
|
||||
|
||||
[mrmlnc.vscode-scss-0.10.0.7z](../../../_resources/mrmlnc.vscode-scss-0.10.0.7z)
|
||||
|
||||
|
||||
|
||||
[mrrefactoring.polacode-fixed-edition-0.3.6.7z](../../../_resources/mrrefactoring.polacode-fixed-edition-0.3.6.7z)
|
||||
|
||||
|
||||
|
||||
[naumovs.theme-oceanicnext-0.0.4.7z](../../../_resources/naumovs.theme-oceanicnext-0.0.4.7z)
|
||||
|
||||
|
||||
|
||||
[pkief.material-icon-theme-4.22.0.7z](../../../_resources/pkief.material-icon-theme-4.22.0.7z)
|
||||
|
||||
|
||||
|
||||
[pranaygp.vscode-css-peek-4.2.0.7z](../../../_resources/pranaygp.vscode-css-peek-4.2.0.7z)
|
||||
|
||||
|
||||
|
||||
|
||||
[ritwickdey.live-sass-3.0.0.7z](../../../_resources/ritwickdey.live-sass-3.0.0.7z)
|
||||
|
||||
|
||||
|
||||
[ritwickdey.liveserver-5.7.9.7z](../../../_resources/ritwickdey.liveserver-5.7.9.7z)
|
||||
|
||||
|
||||
|
||||
[sdras.night-owl-2.0.1.7z](../../../_resources/sdras.night-owl-2.0.1.7z)
|
||||
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
intellij
|
||||
|
||||
- multi caret
|
||||
`alt + shift + click`
|
||||
- select all occurrences
|
||||
`Ctrl + Alt + Shift + J `
|
||||
- select next occurence
|
||||
`Alt + J`
|
||||
- move through blocks
|
||||
`alt+shift+up/down arrow key`
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
netbeans
|
||||
|
||||
- mutiple cursor : select one line then use ctrl+ shift + click to have multicursor, in vscode its ctrl + D
|
||||
- move lines through blocks : instead of alt +up/down arrow key in vs code use alt+shift+up/down key
|
||||
- 
|
||||
https://www.mathworks.com/matlabcentral/answers/uploaded_files/1588496/image.gif
|
||||

|
||||
- select next occurence
|
||||
`Ctrl + J`
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
shortcuts
|
||||
|
||||
zed
|
||||
- switch between terminal and editor : Ctrl + `.
|
||||
- switch between terminal and editor and also hide the terminal when losing focus : `Ctrl+J`
|
||||
|
||||
|
||||
vscode
|
||||
- switch between terminal and editor : same as zed
|
||||
|
||||
micro
|
||||
- https://gist.github.com/rochacbruno/9e4f4c471e849276f11562272db446b0
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
silverbullet
|
||||
Links
|
||||
https://silverbullet.md/Plugs
|
||||
|
||||
**Shortcuts**
|
||||
- open page : ctrl+k
|
||||
- settings : ctrl + .
|
||||
- run : ctrl + /
|
||||
|
||||
|
||||
**commands**
|
||||
to share it across all lan devices use this and underhostname type local ip address of device where there r files
|
||||
`silverbullet . --port=3001 --hostname=192.168.29.234`
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
sublime Text
|
||||
|
||||
- Theme - Midnight.sublime-package :
|
||||
|
||||
[Theme - Midnight.sublime-package](../../../_resources/Theme%20-%20Midnight.sublimepackage)
|
||||
- Sublime ES7 React Redux ReactNative JS snippets.sublime-package
|
||||
|
||||
|
||||
[Sublime ES7 React Redux ReactNative JS snippets.sublime-package](../../../_resources/Sublime%20ES7%20React%20Redux%20ReactNative%20JS%20snippets.sublimepackage)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[SideBarEnhancements.sublime-package](../../../_resources/SideBarEnhancements.sublimepackage)
|
||||
|
||||
|
||||
|
||||
[RainbowBrackets.sublime-package](../../../_resources/RainbowBrackets.sublimepackage)
|
||||
|
||||
|
||||
|
||||
[Oceanic Next Color Scheme.sublime-package](../../../_resources/Oceanic%20Next%20Color%20Scheme.sublimepackage)
|
||||
|
||||
|
||||
|
||||
[Material Theme.sublime-package](../../../_resources/Material%20Theme.sublimepackage)
|
||||
|
||||
|
||||
|
||||
[FileIcons.sublime-package](../../../_resources/FileIcons.sublimepackage)
|
||||
|
||||
|
||||
|
||||
[Emmet.sublime-package](../../../_resources/Emmet.sublimepackage)
|
||||
|
||||
|
||||
|
||||
[Babel.sublime-package](../../../_resources/Babel.sublimepackage)
|
||||
|
||||
|
||||
|
||||
[A File Icon.sublime-package](../../../_resources/A%20File%20Icon.sublimepackage)
|
||||
|
||||
41
joplin notion extension/Web Development/DSA/Practice.md
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
Practice
|
||||
|
||||
```js
|
||||
function getDistinct(arr) {
|
||||
const disArr=[]
|
||||
for(let ele of arr){
|
||||
if(!disArr.includes(ele)){
|
||||
disArr.push(ele)
|
||||
}
|
||||
}
|
||||
|
||||
return disArr
|
||||
}
|
||||
|
||||
const arr=[4,6,8,4,8,14,16,14]
|
||||
// console.log(getDistinct(arr))
|
||||
|
||||
|
||||
function sumtotal2(arr,total,set) {
|
||||
if(total == 0){
|
||||
return set;
|
||||
}
|
||||
|
||||
for(let i=0;i < arr.length;i++){
|
||||
console.log('i: ',i)
|
||||
console.log('!set.includes(i ) ',!set.includes(i ))
|
||||
console.log('total: ',total)
|
||||
if(arr[i] <=total && !set.includes(i )){
|
||||
return sumtotal2(arr,total-arr[i], [...set,i])
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function sumtotal(arr,total) {
|
||||
return sumtotal2(arr,total,[])
|
||||
}
|
||||
|
||||
const arr2 = [6,2,1,1,13,1,0,7,10,1,3]
|
||||
console.log(sumtotal(arr2,13))
|
||||
```
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
Email Clients
|
||||
|
||||
https://opensource.com/article/17/7/email-alternatives-thunderbird
|
||||
111
joplin notion extension/Web Development/Extras/7zip.md
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
7zip
|
||||
|
||||
The 7z file format uses a combination of various compression algorithms, with the primary one being LZMA (Lempel-Ziv-Markov chain algorithm). LZMA is known for its high compression ratio and fast decompression. Here is an overview:
|
||||
|
||||
- *LZMA/LZMA2:* This is the default and most commonly used algorithm when creating 7z archives. LZMA2 is an improved version of LZMA, offering better multithreading support.
|
||||
|
||||
- *PPMd:* Stands for Prediction by Partial Matching, which is good at compressing text data.
|
||||
|
||||
- *BCJ/BCJ2:* These are Branch/Call/Jump conversion filters that pre-process executable files to improve compression.
|
||||
|
||||
- *DEFLATE:* A widely used compression algorithm that is also used in ZIP file format.
|
||||
|
||||
- *BZip2:* Another block-sorting compression algorithm that is particularly effective at compressing large text files.
|
||||
|
||||
Here are some technical details of LZMA/LZMA2, in case they are needed for advanced utilization:
|
||||
|
||||
- *Dictionary size:* Highly customizable, allowing the compressor to store patterns, which can dramatically affect compression ratio and memory requirements.
|
||||
|
||||
- *Compression speed versus Decompression speed:* These are adjustable; typically, LZMA offers slower compression speeds but fast decompression speeds.
|
||||
|
||||
- *Multi-threading support:* LZMA2 in particular can utilize multiple processor cores to improve compression speed on modern computers.
|
||||
|
||||
For archival purposes using 7z, it is also possible to enable solid compression, which treats multiple files within the archive as a single data block for potentially better compression ratios.
|
||||
|
||||
Encryption algorithm : AES-256
|
||||
|
||||
Terminal
|
||||
|
||||
https://www.redhat.com/sysadmin/encrypting-decrypting-7zip
|
||||
|
||||
Encrypting
|
||||
```bash
|
||||
$ tar -cf directory.tar <directory>
|
||||
|
||||
$ 7z a -p -mhe=on directory.tar.7z directory.tar
|
||||
or
|
||||
|
||||
7z a -pYourPassword -mhe=on directory.tar.7z directory.tar
|
||||
|
||||
```
|
||||
Here a means adding files to archive
|
||||
mhe=on means header encryption means metadata like file names will be encrypted too
|
||||
For non interactive password typing type password just after `-p` with no space
|
||||
|
||||
also for level of compression
|
||||
`7z a path/to/archive.7z -mx=0|1|3|5|7|9 path/to/file_or_directory`
|
||||
0 means lowest compression while 9 being highest
|
||||
|
||||
|
||||
|
||||
**for exluding directories**
|
||||
To exclude directories when creating a 7z archive, use the
|
||||
-x switch with the ! wildcard operator, and add an r flag (for recursive) to the switch name if the directories might be in subfolders.
|
||||
The basic syntax for creating an archive and excluding a specific directory named exclude_dir is:
|
||||
`7z a archive.7z source_dir/ -xr\!exclude_dir/`
|
||||
dont forget `\` before `!` as ! is reserved for events
|
||||
|
||||
|
||||
Decrypting
|
||||
|
||||
```bash
|
||||
7z x archive.7z
|
||||
```
|
||||
here x means extracting
|
||||
|
||||
mroe flags
|
||||
- `-aoa`: Overwrite All existing files without asking
|
||||
- `-aos`: Skip extracting any files that already exist (prevents replacing).
|
||||
- `-aou`: Auto-rename the extracted file (e.g., file_1.txt) if the target name exists.
|
||||
- `-aot`: Auto-rename the existing file and extract the new one.
|
||||
|
||||
|
||||
**for splitting**
|
||||
`7z a -v100m archive.7z my_folder/`
|
||||
|
||||
for mass compression of folders
|
||||
```sh
|
||||
#!/bin/bash
|
||||
|
||||
# Check if 7z is installed
|
||||
if ! command -v 7z &> /dev/null
|
||||
then
|
||||
echo "7z command not found! Please install 7zip."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Loop through all directories in the current directory
|
||||
for dir in */; do
|
||||
# Make sure it's a directory
|
||||
if [ -d "$dir" ]; then
|
||||
# Remove the trailing slash from the directory name
|
||||
dir_name=${dir%/}
|
||||
|
||||
# Create a .7z archive for each directory
|
||||
echo "Creating archive for $dir_name..."
|
||||
7z a "${dir_name}.7z" "$dir_name"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "Done!"
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
to print only filepaths instead of other info
|
||||
`7z l -ba archive.7z | grep -oP '(?<=^.{53}).*'`
|
||||
from
|
||||
https://stackoverflow.com/questions/55355466/7z-list-only-filenames
|
||||
to list only top level use this
|
||||
`7z l -ba archive.7z | grep -oP '(?<=^.{53}).*' | grep -v '/'`
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
Android emulator on linux
|
||||
|
||||
- https://repodev.com/blog/install-android-sdk-without-android-studio
|
||||
- https://stackoverflow.com/questions/70752639/i-need-to-install-android-api-30-but-i-cannot-see-that-api-in-the-sdk-platform
|
||||
https://dl.google.com/android/repository/sys-img/google_apis/x86-30_r09.zip : for downloadng system images
|
||||
https://androidsdkmanager.azurewebsites.net/SDKPlatform
|
||||
|
||||
|
||||
- Download commandlinetools and gradle
|
||||
https://www.mediafire.com/file/zjubjy2d2nmblwf/commandlinetools-linux-10406996_latest.zip/file
|
||||
https://www.mediafire.com/file/26sokfserayh28a/gradle-8.5-bin.zip/file
|
||||
|
||||
Or use official sites
|
||||
https://developer.android.com/studio/index.html#command-line-tools-only
|
||||
https://dl.google.com/android/repository/commandlinetools-linux-9477386_latest.zip : ddl link for cmdtools
|
||||
https://gradle.org/releases/ : for gradle
|
||||
compatibility matrix:
|
||||
https://docs.gradle.org/current/userguide/compatibility.html
|
||||
|
||||
- Files hierarchy
|
||||
```
|
||||
/home/username/bin/android/sdk/cmdline-tools/latest/
|
||||
|_bin/
|
||||
|_lib/
|
||||
|_NOTICE.txt
|
||||
|_source.properties
|
||||
|
||||
/home/username/bin/android/gradle/gradle-x.x.x/
|
||||
|_bin/
|
||||
|_docs/
|
||||
|_init.d/
|
||||
|_lib/
|
||||
|_src/
|
||||
|_LICENSE
|
||||
|_NOTICE
|
||||
|_README
|
||||
```
|
||||
- Go to bin directory for cmdtools
|
||||
Then
|
||||
` ./sdkmanager "platforms;android-30" "system-images;android-30;google_apis;x86_64" "platform-tools"`
|
||||
`./sdkmanager --licenses`
|
||||
Also install these
|
||||
`sudo pacman -S libmtp android-tools android-udev`
|
||||
|
||||
- Add path in `.bashrc`
|
||||
```
|
||||
vi ~/.bashrc
|
||||
# Android SDK files
|
||||
export ANDROID_HOME="$HOME/bin/android/sdk"
|
||||
export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools
|
||||
# Gradle
|
||||
export PATH=$PATH:$HOME/bin/android/gradle/gradle-x.x/bin
|
||||
```
|
||||
|
||||
- Running
|
||||
|
||||
Create avd
|
||||
`avdmanager create avd -n image_v29 -k "system-images;android-29;google_apis;x86_64"`
|
||||
if there is error ie `emulator` must be installed then use this
|
||||
`./sdkmanager --channel=3 emulator`
|
||||
then
|
||||
`avdmanager list avd`
|
||||
|
||||
Start it by going to emulator directory then
|
||||
`./emulator -avd image_v29`
|
||||
|
||||
|
||||
- Android versions
|
||||
[android versions](../../../undefined)
|
||||
or
|
||||
https://developer.android.com/tools/releases/platforms
|
||||
|
||||
Open SDK Manager: First, locate and open the SDK Manager. You can find it in the tools directory of your Android SDK installation.
|
||||
|
||||
Launch SDK Manager: Run the sdkmanager command in your terminal or command prompt. Navigate to the tools/bin directory within your Android SDK installation and use the following command:
|
||||
|
||||
`sdkmanager --list`
|
||||
|
||||
This command will list all available packages and their versions.
|
||||
|
||||
Select and Install Previous Android Versions: Once you see the list of available packages, you can find the specific version you want to install. For instance, to install Android 9.0 (API level 28):
|
||||
|
||||
`sdkmanager "platforms;android-28"`
|
||||
|
||||
Replace "platforms;android-28" with the appropriate package name of the desired Android version. This command will download and install Android 9.0 (API level 28).
|
||||
|
||||
|
||||
Additional Components: If you need additional components such as system images or tools for a specific version, you can install them using similar commands:
|
||||
|
||||
|
||||
`sdkmanager "system-images;android-28;google_apis;x86_64"`
|
||||
|
||||
Again, adjust the package name to match the specific version and components you require.
|
||||
|
||||
|
||||
|
||||
22
joplin notion extension/Web Development/Extras/Cons.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
Cons
|
||||
|
||||
|
||||
- Firefox
|
||||
1. githib css not loading properly also its binary cant be downloaded most of times
|
||||
2.
|
||||

|
||||
3. User have to use firefox version 68.11 to able to install extension from xpi file
|
||||
or use this
|
||||
https://www.maketecheasier.com/install-addon-firefox-android/
|
||||
|
||||
|
||||
- Linux
|
||||
1. windows handles battery , hidpi and multiple screens a bit better.
|
||||
2. Poor audio and video linux
|
||||
3. wine is pain to seup and still performance issues in games
|
||||
4. no IDM,winrar,spytify
|
||||
|
||||
signal
|
||||
ya. but signal do have 2 cons.
|
||||
1. it dont have option to store media files in internal storage
|
||||
2. u cant transfer chats from iphone to android and vice versa
|
||||
15
joplin notion extension/Web Development/Extras/DRM.md
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
|
||||
- https://m.youtube.com/watch?v=YNUSxFX4elY the worst drm system in modern times
|
||||
- SafetyNet (Android one)
|
||||
Perhaps the most telling line of the explainer is that it "takes inspiration from existing native attestation signals such as [Apple's] App Attest and the [Android] Play Integrity API." Play Integrity (formerly called "SafetyNet") is an Android API that lets apps find out if your device has been rooted. Root access allows you full control over the device that you purchased, and a lot of app developers don't like that. So if you root an Android phone and get flagged by the Android Integrity API, several types of apps will just refuse to run. You'll generally be locked out of banking apps, Google Wallet, online games, Snapchat, and some media apps like Netflix. You could be using root access to cheat at games or phish banking data, but you could also just want root to customize your device, remove crapware, or have a viable backup system. Play Integrity doesn't care and will lock you out of those apps either way. Google wants the same thing for the web.
|
||||
|
||||
|
||||
- WEI
|
||||
|
||||
|
||||
[Google’s nightmare “Web Integrity API” wants a DRM gatekeeper for the web _ Ars Technica (11_2_2023 12_48_03 PM).html](../../../_resources/Google’s%20nightmare%20“Web%20Integrity%20API”%20wants%20a%20DRM.html)
|
||||
Google's plan is that, during a webpage transaction, the web server could require you to pass an "environment attestation" test before you get any data. At this point your browser would contact a "third-party" attestation server, and you would need to pass some kind of test. If you passed, you would get a signed "IntegrityToken" that verifies your environment is unmodified and points to the content you wanted unlocked. You bring this back to the web server, and if the server trusts the attestation company, you get the content unlocked and finally get a response with the data you wanted.
|
||||
|
||||
and how exactly attestation test will verify we dont know that so that we cant think of someway to bypass it
|
||||
|
||||
|
||||
184
joplin notion extension/Web Development/Extras/Docker.md
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
Docker
|
||||
|
||||
- Installing docker
|
||||
https://itsfoss.com/install-docker-arch-linux/
|
||||
|
||||
- Configuration
|
||||
- Add user to docker group
|
||||
`sudo usermod -aG docker $USER`
|
||||
- Log out and Log Back In
|
||||
After adding your user to the Docker group, you need to either log out and log back in or reboot your system. This step is necessary for the group changes to take effect. An alternative is to use the following command to apply the group change immediately:
|
||||
`newgrp docker`
|
||||
|
||||
- If again needed a permission then
|
||||
- Check Docker Daemon Permissions
|
||||
`ls -l /var/run/docker.sock`
|
||||
The output should show that the group is set to docker. If not, you can adjust the permissions with:
|
||||
`sudo chown root:docker /var/run/docker.sock`
|
||||
|
||||
|
||||
|
||||
- To list images use
|
||||
`docker images`
|
||||
- To list containers use
|
||||
`docker ps`
|
||||
|
||||
- To delete container or image forcefully respectively
|
||||
`docker rm -f <container_id>` and `docker rmi -f <images_id>`
|
||||
- Issues
|
||||
https://stackoverflow.com/questions/51188657/image-is-being-used-by-stopped-container-error
|
||||
building image:
|
||||
|
||||
`docker build -t username/first_app:1.0`
|
||||
|
||||
it will produce an output and will produce image starting with sha……
|
||||
|
||||
To run the image use:
|
||||
`docker run <image_name/code>`
|
||||
|
||||
Now if we try to run it with port(here in eg port is 8080) then it wont run because by default its not accessible outside container so to expose it we can use port forwarding.
|
||||
|
||||
`docker run -p 5000:8080 <image_name/code>`
|
||||
|
||||
port 8080 of container is forwarded to port 5000 of outside container. 5000:8080 is mapping
|
||||
|
||||
- For publishing
|
||||
|
||||
Now login through the CLI by executing:
|
||||
|
||||
```
|
||||
docker login
|
||||
```
|
||||
|
||||
Push your Docker Image to the Docker Hub repository with the following command:
|
||||
|
||||
```
|
||||
docker image push <repository>/<image>:<tag>
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
docker image push dhanushkamath/dockerize-node:1.0.0
|
||||
```
|
||||
|
||||
You’ve successfully published your first image to the world!
|
||||
|
||||
Running this container on a different computer that has Docker only requires a single command:
|
||||
|
||||
```
|
||||
docker run dhanushkamath/dockerize-node:1.0.0
|
||||
```
|
||||
- Reducing image size
|
||||
https://devopscube.com/reduce-docker-image-size/
|
||||
|
||||
|
||||
**Dockerhub**
|
||||
Anonymous and Free Docker Hub users are limited to 100 and 200 container image pull requests per six hours.
|
||||

|
||||
|
||||
When using docker login the auth token will be stored in `SHOME/.docker/config.json` so using different users we can login to different accounts simuntaneously
|
||||
|
||||
**Pushing images to dockerhub**
|
||||
- When we create image using `docker build -t image_name:tagname .` then we get a image of name specified. To push image in dockerhub, image name should be in format `username/repo:tagname` . So instead of creating image again with same format we can create a link/tag to local image with
|
||||
`docker tag local_image_name:tagname username/repo_name:tagname`. so for same image we have 2 different names. Now we can just push with
|
||||
`docker image push username/repo_name:tagname`
|
||||
Then finally to download it use
|
||||
`docker pull username/repo_name:tagname`
|
||||
|
||||
|
||||
### Docker container with multiple node instances
|
||||
- Use pm2 for it
|
||||
Structure of files in host
|
||||
```text
|
||||
puppetter_test
|
||||
index.js
|
||||
ecosystem.config.js
|
||||
... (other files)
|
||||
ytDownloadSpace
|
||||
app.js
|
||||
... (other files)
|
||||
ytdlApi
|
||||
app.js
|
||||
... (other files)
|
||||
Dockerfile
|
||||
```
|
||||
Dockerfile
|
||||
```yaml
|
||||
FROM alpine
|
||||
RUN apk add --update nodejs npm bash
|
||||
|
||||
# App 1
|
||||
WORKDIR /src/puppetter_test
|
||||
COPY puppetter_test/ ./
|
||||
RUN npm install
|
||||
|
||||
# App 2
|
||||
WORKDIR /src/ytDownloadSpace
|
||||
COPY ytDownloadSpace ./
|
||||
RUN npm install
|
||||
|
||||
|
||||
# App 3
|
||||
WORKDIR /src/ytdlApi
|
||||
COPY ytdlApi/ ./
|
||||
RUN npm install
|
||||
|
||||
|
||||
|
||||
|
||||
RUN npm install -g pm2
|
||||
|
||||
#config file
|
||||
WORKDIR /src/puppetter_test
|
||||
EXPOSE 8081
|
||||
# starting pm2 with --no-daemon flag to keep it running in foreground
|
||||
# instead of background to prevent docker container from stopping
|
||||
CMD pm2 start ecosystem.config.js --no-daemon
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
`ecosystem.config.js`
|
||||
```js
|
||||
module.exports = {
|
||||
apps: [
|
||||
{
|
||||
name: 'main',
|
||||
script: 'index.js',
|
||||
watch: true,
|
||||
env: {
|
||||
NODE_ENV: 'production',
|
||||
PORT: 8081
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ytdownloadspace',
|
||||
script: '../ytDownloadSpace/app.js',
|
||||
watch: true,
|
||||
env: {
|
||||
NODE_ENV: 'production',
|
||||
PORT: 8080
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ytdlApi',
|
||||
script: '../ytdlApi/app.js',
|
||||
watch: true,
|
||||
env: {
|
||||
NODE_ENV: 'production',
|
||||
PORT: 8083
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
```
|
||||
- docker import and export images
|
||||
https://stackoverflow.com/questions/24482822/how-to-share-my-docker-image-without-using-the-docker-hub
|
||||
Based on this blog, one could share a docker image without a docker registry by executing:
|
||||
`docker save --output latestversion-1.0.0.tar dockerregistry/latestversion:1.0.0`
|
||||
Once this command has been completed, one could copy the image to a server and import it as follows:
|
||||
`docker load --input latestversion-1.0.0.tar`
|
||||
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
Basics
|
||||
https://www.youtube.com/watch?v=kTp5xUtcalw&t=335s : freecodecamp ones
|
||||
https://www.youtube.com/playlist?list=PLinedj3B30sDvBfeK9EPz9pcJNlM0f3ph : piyush garg ones
|
||||
https://www.youtube.com/watch?v=pR5jOQnfNtY : docker in mobile
|
||||
|
||||
### Microservices architecture
|
||||
- A variant of the service oriented architecture(SOA) structural style - arranges an aplication as a collection of loosely coupled services
|
||||
- In a microservices architecture, services are fine-grained and the protocols are lightweight.
|
||||
|
||||
|
||||
### Monolithic architecture
|
||||
- built as a single unt
|
||||
- deployed as a single unit (building time would be high)
|
||||
- duplicated on each server
|
||||
- ex: 3-tier apps like MVC architecture
|
||||
|
||||
|
||||
### Microservices
|
||||
- Breaking big system into smaller parts and each with its own responsibility.
|
||||
- Scale these smaller pieces independtly from each other
|
||||
- Loosely coupled : No strong bond because we expose functionality though api
|
||||
- Enable autonomous development by different teams, languages : Can be written by smaller teams so outsourcing and independent development is possible so they can even use different programming languages too.
|
||||
- Each microservices can have its own separate database
|
||||
|
||||
|
||||
### Diagrams
|
||||
Monolithic architecture
|
||||

|
||||
|
||||
For deploying in more servers
|
||||

|
||||
|
||||
|
||||
Microservice architecture
|
||||

|
||||
|
||||
For scaling
|
||||

|
||||
|
||||
Monolith to microservices
|
||||

|
||||
|
||||
|
||||
## Microservice anti patterns
|
||||
|
||||
### Challenges
|
||||
- Risk of unneccessary complexities when converting monlithic to so many microservices
|
||||
- numerous services can be impacted too
|
||||
- Security of microsercices is also a challenge
|
||||
|
||||
|
||||
### Microservices Benefits
|
||||
- Improved fault isolation : wont take whole system down if one of them go down
|
||||
- less vendor lock in or technology in bcz of use of open source technologies
|
||||
- Easier to understand
|
||||
- Smaller and faster development
|
||||
- Scalibility
|
||||
|
||||
### Microservices - Drawbacks
|
||||
- Complexity is added to resolve complexity issues
|
||||
So need to start it slowly with a pace that everyone can keep it
|
||||
- Its easier to test independent services but it is also necessary to test whole system to check if they r communicating with each other properly or not.
|
||||
- Is deployment really simpler
|
||||
- challenges with multiple times
|
||||
- One microservice update other microservices too
|
||||
- Need to have multiple databases too
|
||||
- Latency issues : As there r so many routes needs to be taken as each microservice will call api to talk to each other so there will be latency issues too
|
||||
- Transient errors : Sometimes between calls there maybe errors which can be fixed with retry so make sure to do that
|
||||
- Multiple point of failure
|
||||
- Security issues as when communicating we may not want to expose everything and needed to be take care of that
|
||||
|
||||
|
||||
|
||||
## Cloud Natives
|
||||
- Cloud natives uses containers, service meshes, microservices, immutable infrastructure and declaritive APIs.
|
||||
Immutable infrastructure means instead of updating it we replace with newer versions.
|
||||
These technologies is used to build and run scalable applications in modern, dynamic environments such as public, private and hybrid cloud.
|
||||
- use of metrics, creation and updation are automated and frequent deployment of eye impact changes
|
||||
- using of open source projects
|
||||
|
||||
|
||||
### Cloud native concepts
|
||||
- Speed and agility
|
||||
- Application architecture
|
||||

|
||||
- Mentality : Pets vs Cattle
|
||||
- Unlike VM where we need to take care it, infrastructure in this immutable and disposable like cattle
|
||||
- Provisioned in minites and destroyed on demand
|
||||
- Never updated or repaired, just re-provisioned/replaced.
|
||||
- Cloud Native Trail Map
|
||||
- Breaks journey into measurable objects
|
||||
- Containerization
|
||||
- Done through docker containers
|
||||
- CI/CD
|
||||
- Setup Continuous Integration/Continuous Delivery (CI/CD) so changes to source code automatically result in a new container being built, tested and deployed to staging and eventually perhaps to production
|
||||
- Orchestration : Eg : Kubernetes and deploy using help chart
|
||||
- Obervability and analysis : Monitoring, logging and tracing .
|
||||
- Service proxy, discovery and mesh : Eg :envoy, CoreDNS, LinkerD
|
||||
- Networking, Policy and Security: Eg : CNI, Open policy agent, Falco
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
Containers
|
||||
|
||||
A container is a unit of deployment. It contains everything for a code to run. We take the container, push them on server and it should run. Container contains code, runtime, system tools and system libraries. It can have external dependencies too like database or cache
|
||||
|
||||
Reason of using container
|
||||
- Move faster by deploying smaller units
|
||||
- Use few resources
|
||||
- Fit more into the same host
|
||||
- Faster automation when using CI/CD techniques
|
||||
- Portability
|
||||
- Isolation
|
||||
|
||||
Virtual machine vs containers
|
||||
- VM runs on hardware where OS is installed. OS hypervisor lets us create virtual machine where we install an OS . So we would have bios and firmware too as it is hardware even though it is virtual. VM is basically **virtualize the hardware**
|
||||
- In containers we still have hardware and OS. Container runtime is installed in the OS instead of creating virtual machine.Container images are run in the memory. Container dont need to boot as it uses the HOST kernel and they dont have to boot. They will need small disk space as there is no OS with few megabytes of hard disk and 64 or 128MB of RAM required.
|
||||

|
||||

|
||||
|
||||
|
||||
|
||||
### More
|
||||
Containers are made up of layers
|
||||

|
||||
Eg : `docker pull` command will download container image and each layer will be downloaded individually and each layer has unique id. If a layer already exist then it wont download again as docker uses local cache to store container's images.
|
||||
Advantage is if we download version 2 then it wont download whole image, just the layers which is not present
|
||||
So a goal is to create docker container images which smallest number of layers possible
|
||||
Layers in the docker : Top one is both read-write but lower ones in read-only.
|
||||
|
||||
|
||||
### Container registry
|
||||
- Centralized container repository
|
||||
- Think Github but for containers.
|
||||
- Docker hub is a great example
|
||||
- Major providers have container registry services like AWS, azure and GCP.
|
||||
|
||||
|
||||
**Orchestrator**
|
||||
- Allow us to Manage, scale monitor the containers that we run on servers
|
||||
- We can use our own like kubernates, swarm, service fabric
|
||||
- or we can use a managed cluster offered by cloud providers.
|
||||
|
||||
146
joplin notion extension/Web Development/Extras/Docker/Docker.md
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
Docker
|
||||
- Docker is both the company and platform
|
||||
- An open source container runtime
|
||||
- Cross platform desktop support
|
||||
- Command line tool
|
||||
- "Dockerfile" file format for building container images
|
||||
- Windows let us create both windows and linux containers
|
||||
|
||||
**Docker cli commands**
|
||||
- `docker info` : display system information
|
||||
- `docker version`
|
||||
- `docker login` : by default it will login to dockerhub
|
||||
|
||||
Docker running commands
|
||||
- `docker run [imageName]` : execute image in memory. image is not present in cache, it will be downloaded automatically.
|
||||
there is another flag named `--name` to give name to docker instance which will run. if we dont provide docker will generate random name.
|
||||
eg : `docker run --name web [imageName] ` here web is the name
|
||||
**imposing limits on docker instance**
|
||||
`docker run --memory="256m" nginx`
|
||||
`docker run --cpus=".5" nginx`
|
||||
- `docker run -d [imageName]` : to run container in background so u can still use the terminal
|
||||
- `docker stop [containerName]` : will stop the execution but it will still in memory
|
||||
- `docker kill [containerName]` : to remove container in memory which r stuck
|
||||
- `docker image inspect` : useful for debugging
|
||||
- **Note**: When we use run we create a container from the image. Also when we use flags with `run` certain configuration are set too To stop execution we can use stop command but using start we can again start it with same configuration too.
|
||||

|
||||
|
||||
|
||||
**Usage**
|
||||

|
||||
**Attach shells**
|
||||

|
||||
Working command
|
||||
`docker exec -it web3 bash`
|
||||
here `web3` is container name which is running in background
|
||||
for executing commands for background running containers
|
||||
`podman exec web3 bash -c "ls"`
|
||||
for non running containers
|
||||
`docker run -it --name archc8 archlinux:latest /usr/bin/bash`
|
||||
for non running containers so basically creating a new container
|
||||
`docker run -it alpine:latest sh -c "apk add --update bash && exec bash"`
|
||||
By using the `--rm` flag with either the docker run or docker create command, you ensure that the container is automatically removed once it stops
|
||||
|
||||
**to start distro and keep it running**
|
||||
`podman run -itd --name ubuntu1 ubuntu /bin/bash`
|
||||
**Clearing things up**
|
||||

|
||||
For removing containers, they must be stopped first
|
||||
|
||||
|
||||
|
||||
## Docker build containers
|
||||
- 
|
||||
- `docker build -t ngthml:1.0 dockers/` (dockers folder contain Dockerfile)
|
||||
- If Dockerfile name is not DockerFile then specify that name with `-f` flag.
|
||||
- Eg of dockerfile
|
||||
```text
|
||||
FROM nginx:alpine
|
||||
COPY . /usr/share/nginx/html
|
||||
```
|
||||
FROM command specify base image and when we build something we use image which already exist. nginx:alpine is very lightweight
|
||||
then copy whole folder containing Dockerfile to `/usr/share/nginx/html` of alpine
|
||||
- Nodejs Dockerfile
|
||||
alpine is very lightweight and there isnt even bash installed so we cant have interactive shell too. But we can install bash by
|
||||
`docker exec -it node_hello apk add --update bash`
|
||||
or including it in `RUN apk add --update nodejs npm bash`
|
||||
```text
|
||||
FROM alpine
|
||||
RUN apk add --update nodejs npm
|
||||
COPY . /src
|
||||
WORKDIR /src
|
||||
RUN npm install
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["node", "./app.js"]
|
||||
```
|
||||
- RUN apk .... : Using RUN we can execute commands when generating container. in this case using apk package manager of alpine we are installing nodejs and npm.
|
||||
Then we copy current folder to `/src` and making it as work directory too.
|
||||
- `WORKDIR` is a combination or cd and mkdir as we dont need to make directory too as workdir will handle it. `RUN cd` wont have effect as when using RUN commands will be run in different shell so thats why using WORKDIR is preferred
|
||||
WORKDIR / changes the working directory for future commands.
|
||||
RUN cd / has no impact on the subsequent RUNs.
|
||||
- EXPOSE will make sure which port shoould be accessible by other containers or host system
|
||||
- ENTRYPOINT means commands that will run when the container start
|
||||
**Difference between run,cmd and entrypoint**
|
||||
https://www.bmc.com/blogs/docker-cmd-vs-entrypoint/
|
||||
https://www.cloudbees.com/blog/understanding-dockers-cmd-and-entrypoint-instructions
|
||||
- RUN. Mainly used to build images and install applications and packages, RUN builds a new layer over an existing image by committing the results.
|
||||
- CMD. Sets default parameters that can be overridden from the Docker Command Line Interface (CLI) when a container is running. eg : `cmd node app.js`
|
||||
- ENTRYPOINT. Default parameters that cannot be overridden when Docker Containers run with CLI parameters.
|
||||
**Example**
|
||||
if there is `cmd node app.js` and
|
||||
`docker run nodecontainer node app2.js`
|
||||
then in docker container it will be
|
||||
`node app2.js` as it will override
|
||||
|
||||
if there is `entrypoint ["node", "app.js"]` and
|
||||
`docker run nodecontainer node app2.js`
|
||||
then in docker container it will be
|
||||
```bash
|
||||
node app.js
|
||||
node app2.js
|
||||
```
|
||||
instead of overriding `node app2.js` is appended
|
||||
- docker tag
|
||||
- Assign a name and tag to a specific image ID:
|
||||
`docker tag id name:tag`
|
||||
|
||||
- Assign a tag to a specific image:
|
||||
`docker tag image:current_tag image:new_tag`
|
||||
- docker cp
|
||||
to copy files from docker container to host
|
||||
`docker cp <containerId>:/file/path/within/container /host/path/target`
|
||||
eg:
|
||||
`docker cp node_hello_sh:/ alpine_node/`
|
||||
|
||||
to copy files from host to docker container
|
||||
`docker cp /host/path/target container_id:/file/path/within/container`
|
||||
eg:
|
||||
`docker cp foo.txt container_id:/foo.txt`
|
||||
- docker logs
|
||||
`docker logs <container_id>`
|
||||
or when creating container
|
||||
`docker run --log-level=debug ...`
|
||||
- Expose port of already created container
|
||||
While it is not possible to expose port we can access it by `http://container_ip:PORT`. we can find container ip by
|
||||
`docker inspect container_name | grep IPAddress` . run `docker ps` to find container name first
|
||||
- environment variables when starting a container from image
|
||||
`docker run --name my-tomcat -p 127.0.0.1:8080:8080 -e APP_DB_DB=mydb -e APP_DB_USER=dbuser -e APP_DB_PASS=dbpass --link mongo-myapp:mongo -v /path-to/tomcat/webapps:/usr/local/tomcat/webapps -d tomcat:8-jre8-alpine`
|
||||
- creating image from container
|
||||
after making some changes in container we can create its own image too
|
||||
`docker commit nginx_base` where nginx_base is name of container
|
||||
this will create image but it have no tag so crating its tag with
|
||||
`docker tag 0c17f0798823 hello_world_nginx`
|
||||
or simply add tag when creating image
|
||||
`docker commit nginx_base hello_world_nginx`
|
||||
here hello_world_nginx is name of image
|
||||
- docker volume
|
||||
`docker run -v $PWD:/data -it archivebox/archivebox init --setup`
|
||||
`-v $PWD:/data`: This mounts the current working directory (represented by $PWD, which is a shell variable) on your host machine to the /data directory inside the Docker container. This is crucial because it allows ArchiveBox to store its data (archived websites, indexes, etc.) persistently on your host machine, even if the container is stopped or removed. The -v flag stands for "volume."
|
||||
- docker import and export images
|
||||
https://stackoverflow.com/questions/24482822/how-to-share-my-docker-image-without-using-the-docker-hub
|
||||
Based on this blog, one could share a docker image without a docker registry by executing:
|
||||
`docker save --output latestversion-1.0.0.tar dockerregistry/latestversion:1.0.0`
|
||||
Once this command has been completed, one could copy the image to a server and import it as follows:
|
||||
`docker load --input latestversion-1.0.0.tar`
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
podman
|
||||
https://www.youtube.com/watch?v=Z5uBcczJxUY : Stop Using Docker. Use Open Source Instead
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
projects
|
||||
|
||||
## spring quiz app
|
||||
- location : `/home/hpes/Videos/imp/java/spring/genz/quiz_back_docker-compose`
|
||||
**following will not work**
|
||||
- to go to bash use this
|
||||
`docker run --rm -it --name quiz-app quiz-app-docker:1.0 bash`
|
||||
- run app (use -d for detach mode)
|
||||
`docker run -p 8085:8080 --rm --name quiz-app quiz-app-docker:1.0`
|
||||
- build
|
||||
`docker build -t quiz-app:1.0 .`
|
||||
- Dockerfile
|
||||
```
|
||||
FROM alpine:latest
|
||||
RUN apk add --update bash openjdk17 maven mariadb mariadb-client
|
||||
COPY . /spring-app
|
||||
WORKDIR /spring-app
|
||||
RUN mvn package
|
||||
# Initialize MySQL database (this step will only run the first time)
|
||||
RUN mysql_install_db --user=root --basedir=/usr --datadir=/var/lib/mysql
|
||||
RUN mysqld_safe --user=root & \
|
||||
sleep 3 && \
|
||||
mysql -e "create database quiz;" && \
|
||||
mysql quiz < quiz.sql
|
||||
EXPOSE 8080
|
||||
RUN chmod +x entrypoint.sh
|
||||
# Start the MySQL service and your backend
|
||||
CMD sh /spring-app/entrypoint.sh
|
||||
|
||||
```
|
||||
|
||||
**docker compose method** (1.3 gb)
|
||||
docker-compose.yml
|
||||
```yml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:latest # You can use a different version if necessary
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: strong_password
|
||||
ports:
|
||||
- "3307:3306" # Expose MySQL on port 3307
|
||||
volumes:
|
||||
- /var/lib/docker/volumes/mysql_app_data/_data:/var/lib/mysql # Persist MySQL data
|
||||
|
||||
spring-app:
|
||||
build: .
|
||||
environment:
|
||||
SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/quiz?allowMultiQueries=true
|
||||
SPRING_DATASOURCE_USERNAME: root
|
||||
SPRING_DATASOURCE_PASSWORD: strong_password
|
||||
ports:
|
||||
- "8085:8080" # Expose Spring Boot app on port 8080
|
||||
depends_on:
|
||||
- mysql # Ensure MySQL starts before Spring Boot app
|
||||
|
||||
```
|
||||
|
||||
Dockerfile for spring-app
|
||||
```
|
||||
FROM alpine:latest
|
||||
RUN apk add --update bash openjdk17 maven
|
||||
COPY . /spring-app
|
||||
WORKDIR /spring-app
|
||||
RUN mvn package
|
||||
EXPOSE 8080
|
||||
|
||||
|
||||
CMD java -jar target/demo-0.0.1-SNAPSHOT.jar
|
||||
|
||||
```
|
||||
|
||||
two commands
|
||||
`docker-compose build` and `docker-compose up`
|
||||
|
||||
|
||||
## youtube playlist downloader
|
||||
200 mb
|
||||
- location : `/home/hpes/Videos/imp/nodejs/production/youtube downloader/`
|
||||
- `docker build -t ytdown:1.0 .`
|
||||
DockerFile
|
||||
```
|
||||
FROM alpine
|
||||
RUN apk add --update nodejs npm bash
|
||||
|
||||
# App 1
|
||||
WORKDIR /src/puppetter_test
|
||||
COPY puppetter_test/ ./
|
||||
RUN npm install
|
||||
|
||||
# App 2
|
||||
WORKDIR /src/ytDownloadSpace
|
||||
COPY ytDownloadSpace ./
|
||||
RUN npm install
|
||||
|
||||
|
||||
# App 3
|
||||
WORKDIR /src/ytdlApi
|
||||
COPY ytdlApi/ ./
|
||||
RUN npm install
|
||||
|
||||
|
||||
|
||||
|
||||
RUN npm install -g pm2
|
||||
|
||||
#config file
|
||||
WORKDIR /src/puppetter_test
|
||||
EXPOSE 8081
|
||||
CMD pm2 start ecosystem.config.js --no-daemon
|
||||
|
||||
# CMD ["node", "app.js"]
|
||||
|
||||
```
|
||||
|
||||
for vps
|
||||
[setup.md](../../../../_resources/setup.md)
|
||||
464
joplin notion extension/Web Development/Extras/Encryption.md
Normal file
|
|
@ -0,0 +1,464 @@
|
|||
- RC4
|
||||
|
||||
- NodeJs
|
||||
|
||||
```jsx
|
||||
const rc4 = require("arc4");
|
||||
const fs=require('fs')
|
||||
|
||||
const data=fs.readFileSync('stacer.jpeg')
|
||||
|
||||
const uData=new Uint8Array(data)
|
||||
|
||||
const key = "123456789123456789";
|
||||
|
||||
// const data = e.target.result;
|
||||
const fSize = data.byteLength;
|
||||
|
||||
const cipher = rc4("arc4", key);
|
||||
|
||||
// const enc = cipher.encodeBuffer(uData);
|
||||
const enc = cipher.encodeArray(uData);
|
||||
console.log("🚀 ~ file: script.js:76 ~ fr.addEventListener ~ enc:", enc);
|
||||
// const dec = cipher.decodeBuffer(enc);
|
||||
const dec = cipher.decodeArray(enc);
|
||||
console.log("🚀 ~ file: script.js:78 ~ fr.addEventListener ~ dec:", dec);
|
||||
|
||||
const decBuffer=Buffer.from(dec)
|
||||
fs.writeFileSync('stacerdec.jpeg',decBuffer)
|
||||
```
|
||||
|
||||
- Javascript(Client side)
|
||||
|
||||
```jsx
|
||||
// Function to read a file and return its content as a promise
|
||||
function readFile(fileInput) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const file = fileInput.files[0];
|
||||
if (!file) {
|
||||
reject("No file selected");
|
||||
return;
|
||||
}
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
resolve(event.target.result);
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
});
|
||||
}
|
||||
|
||||
// Function to save encrypted data to a file
|
||||
function saveEncryptedFile(encryptedData) {
|
||||
const blob = new Blob([encryptedData]);
|
||||
const a = document.createElement("a");
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.download = "encrypted_file.enc";
|
||||
a.click();
|
||||
}
|
||||
|
||||
// Function to save decrypted data to a file
|
||||
function saveDecryptedFile(decryptedData) {
|
||||
const blob = new Blob([decryptedData]);
|
||||
const a = document.createElement("a");
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.download = "decrypted_file.txt"; // Change the file extension as needed
|
||||
a.click();
|
||||
}
|
||||
|
||||
// Function to encrypt a file using ARC4
|
||||
async function encryptFile() {
|
||||
const fileInput = document.getElementById("fileInput");
|
||||
const fileContent = await readFile(fileInput);
|
||||
const rc4 = ARC4("your_secret_key");
|
||||
const encryptedData = rc4.encrypt(new Uint8Array(fileContent));
|
||||
saveEncryptedFile(encryptedData);
|
||||
}
|
||||
|
||||
// Function to decrypt an encrypted file using ARC4
|
||||
async function decryptFile() {
|
||||
const encryptedFileInput = document.getElementById("encryptedFileInput");
|
||||
const encryptedContent = await readFile(encryptedFileInput);
|
||||
const rc4 = ARC4("your_secret_key");
|
||||
const decryptedData = rc4.decrypt(new Uint8Array(encryptedContent));
|
||||
saveDecryptedFile(decryptedData);
|
||||
}
|
||||
```
|
||||
|
||||
- AES
|
||||
|
||||
```jsx
|
||||
// merging splitted Uint8arrays to single one
|
||||
const mergeTo1D=(uarrays)=>{
|
||||
if(uarrays.length===0)
|
||||
{
|
||||
return []
|
||||
}
|
||||
const sum=0
|
||||
for(let urray of urray)
|
||||
{
|
||||
sum+=urray/length
|
||||
}
|
||||
|
||||
const mergedArray= new Uint8Array(sum)
|
||||
|
||||
mergedArray.set(uarrays[0],0)
|
||||
|
||||
for(let i=1;i<uarrays.length;i++)
|
||||
{
|
||||
mergedArray.set(uarrays[i],uarrays[i-1].length)
|
||||
}
|
||||
|
||||
return mergedArray
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
- nodejs
|
||||
Streamlined encyption using native crypto module of nodejs
|
||||
|
||||
encryption.js
|
||||
|
||||
```jsx
|
||||
const fs = require("fs");
|
||||
const crypto = require("crypto");
|
||||
const CryptoJS = require("crypto-js");
|
||||
require("crypto-js/aes");
|
||||
|
||||
// const fileName='redis-stack-server-7.2.0-v4-x86_64.AppImage'
|
||||
// const fileName='Joplin-2.12.18.AppImage'
|
||||
// const fileName='stacer.jpeg'
|
||||
const fileName='Black.Mirror.S06E01.Joan.Is.Awful.720p.10Bit.Hindi.English.Esubs.MoviesMod.org.mkv'
|
||||
|
||||
// Input and output file paths
|
||||
const inputFile = fileName; // Replace with your input file path
|
||||
const outputFile = `${fileName}.enc`; // Replace with your output file path
|
||||
|
||||
// Encryption parameters
|
||||
// const key = "YourSecretKey"; // Replace with your encryption key
|
||||
const key = crypto.randomBytes(32);
|
||||
const iv = crypto.randomBytes(16); // Initialization Vector (IV)
|
||||
|
||||
|
||||
fs.writeFileSync('key.bin',key);
|
||||
fs.writeFileSync('iv.bin',iv);
|
||||
|
||||
// console.log('key: ',key.toString())
|
||||
// console.log('iv: ',iv.toString())
|
||||
|
||||
// Create a readable stream for the input file and a writable stream for the output file
|
||||
const inputStream = fs.createReadStream(inputFile);
|
||||
const outputStream = fs.createWriteStream(outputFile);
|
||||
|
||||
// Encrypt and write the file in chunks
|
||||
const encryptionStream = crypto.createCipheriv("aes-256-cbc", Buffer.from(key), iv);
|
||||
inputStream.pipe(encryptionStream).pipe(outputStream);
|
||||
|
||||
// Handle events and errors
|
||||
inputStream.on("error", (err) => console.error("Input Stream Error:", err));
|
||||
outputStream.on("error", (err) => console.error("Output Stream Error:", err));
|
||||
outputStream.on("finish", () => console.log("Encryption completed."));
|
||||
|
||||
// Optionally, you can handle stream close events as well
|
||||
inputStream.on("close", () => console.log("Input stream closed."));
|
||||
outputStream.on("close", () => console.log("Output stream closed."));
|
||||
```
|
||||
|
||||
|
||||
decryption.js
|
||||
|
||||
```jsx
|
||||
const fs = require("fs");
|
||||
const crypto = require("crypto");
|
||||
const CryptoJS = require("crypto-js");
|
||||
require("crypto-js/aes");
|
||||
|
||||
|
||||
// const fileName='Joplin-2.12.18.AppImage'
|
||||
// const fileName='stacer.jpeg'
|
||||
const fileName='Black.Mirror.S06E01.Joan.Is.Awful.720p.10Bit.Hindi.English.Esubs.MoviesMod.org.mkv'
|
||||
|
||||
// Input and output file paths
|
||||
|
||||
const inputFile = `${fileName}.enc`; // Replace with your output file path
|
||||
const outputFile = `${fileName}.dec`; // Replace with your output file path
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const key=fs.readFileSync('key.bin');
|
||||
const iv=fs.readFileSync('iv.bin');
|
||||
|
||||
const inputStream = fs.createReadStream(inputFile);
|
||||
const outputStream = fs.createWriteStream(outputFile);
|
||||
|
||||
// Decrypt and write the file in chunks
|
||||
const decryptionStream = crypto.createDecipheriv("aes-256-cbc", Buffer.from(key), iv);
|
||||
inputStream.pipe(decryptionStream).pipe(outputStream);
|
||||
|
||||
// Handle events and errors
|
||||
inputStream.on("error", (err) => console.error("Input Stream Error:", err));
|
||||
outputStream.on("error", (err) => console.error("Output Stream Error:", err));
|
||||
outputStream.on("finish", () => console.log("Decryption completed."));
|
||||
|
||||
// Optionally, you can handle stream close events as well
|
||||
inputStream.on("close", () => console.log("Input stream closed."));
|
||||
outputStream.on("close", () => console.log("Output stream closed."));
|
||||
```
|
||||
|
||||
- client side javascript(browser)
|
||||
|
||||
encryption.html
|
||||
|
||||
```jsx
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Large File Encryption</title>
|
||||
</head>
|
||||
<body>
|
||||
<input type="file" id="fileInput" >
|
||||
<button id="encryptButton">Encrypt</button>
|
||||
<a id="downloadLink" style="display: none" download="encrypted-file.txt">Download Encrypted File</a>
|
||||
|
||||
<script>
|
||||
const algorithmName="AES-GCM"
|
||||
// const algorithmName="AES-CBC"
|
||||
document.getElementById("encryptButton").addEventListener("click", async () => {
|
||||
const fileInput = document.getElementById("fileInput");
|
||||
const file = fileInput.files[0];
|
||||
if (!file) {
|
||||
alert("Please select a file.");
|
||||
return;
|
||||
}
|
||||
|
||||
const chunkSize = 1024 * 1024; // 1 MB chunks
|
||||
const key = await window.crypto.subtle.generateKey({ name: algorithmName, length: 256 }, true, ["encrypt","decrypt"]);
|
||||
|
||||
const keyData = await window.crypto.subtle.exportKey('jwk', key);
|
||||
|
||||
// Create a data blob with the key data
|
||||
const keyBlob = new Blob([JSON.stringify(keyData)], { type: 'application/json' });
|
||||
|
||||
// Create a download link for the key
|
||||
const keyUrl = URL.createObjectURL(keyBlob);
|
||||
const downloadLink = document.createElement('a');
|
||||
downloadLink.href = keyUrl;
|
||||
downloadLink.download = 'encryption-key.json';
|
||||
downloadLink.click();
|
||||
|
||||
const iv=new Uint8Array(16);
|
||||
|
||||
const ivBlob= new Blob([JSON.stringify(iv)], { type: 'application/json' })
|
||||
const ivUrl=URL.createObjectURL(ivBlob)
|
||||
const ivdownloadlink=document.createElement('a')
|
||||
ivdownloadlink.href= ivUrl
|
||||
ivdownloadlink.download ='encryption-iv.json'
|
||||
ivdownloadlink.click()
|
||||
|
||||
|
||||
|
||||
|
||||
const reader = new FileReader();
|
||||
const fileData = [];
|
||||
let offset = 0;
|
||||
|
||||
reader.onload = async function () {
|
||||
|
||||
// const algorithm= { name: "AES-GCM", iv }
|
||||
const algorithm= { name: algorithmName, iv }
|
||||
console.log('algorithm: ',algorithm)
|
||||
const chunk = new Uint8Array(reader.result);
|
||||
const encryptedChunk = await window.crypto.subtle.encrypt(
|
||||
algorithm,
|
||||
key,
|
||||
chunk
|
||||
);
|
||||
// const encryptedChunk=chunk
|
||||
fileData.push(encryptedChunk);
|
||||
offset += chunk.length;
|
||||
|
||||
if (offset < file.size) {
|
||||
readSlice(offset);
|
||||
} else {
|
||||
// All chunks are encrypted; combine them and provide a download link.
|
||||
const encryptedData = new Blob(fileData, { type: file.type });
|
||||
const url = URL.createObjectURL(encryptedData);
|
||||
const downloadLink = document.getElementById("downloadLink");
|
||||
downloadLink.href = url;
|
||||
downloadLink.style.display = "block";
|
||||
console.log('finished')
|
||||
}
|
||||
};
|
||||
|
||||
function readSlice(offset) {
|
||||
const slice = file.slice(offset, offset + chunkSize);
|
||||
reader.readAsArrayBuffer(slice);
|
||||
}
|
||||
|
||||
readSlice(0);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
|
||||
decryption.js
|
||||
|
||||
```jsx
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>File Decryption</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>File Decryption</h1>
|
||||
|
||||
<!-- Input for the encrypted file -->
|
||||
<input type="file" id="encryptedFileInput" />
|
||||
|
||||
<!-- Input for the encryption key (as JSON) -->
|
||||
<input type="file" id="keyInput" accept=".json" />
|
||||
|
||||
<!-- Input for the IV (as JSON) -->
|
||||
<input type="file" id="ivInput" accept=".json" />
|
||||
|
||||
<button id="decryptButton">Decrypt</button>
|
||||
|
||||
<a id="downloadLink" style="display: none;">Download Decrypted File</a>
|
||||
|
||||
<script>
|
||||
document.getElementById("decryptButton").addEventListener("click", async () => {
|
||||
// Get the encrypted file
|
||||
const encryptedFileInput = document.getElementById("encryptedFileInput");
|
||||
const encryptedFile = encryptedFileInput.files[0];
|
||||
|
||||
// Get the encryption key and IV (as JSON)
|
||||
const keyInput = document.getElementById("keyInput");
|
||||
const ivInput = document.getElementById("ivInput");
|
||||
|
||||
const keyFile = keyInput.files[0];
|
||||
const ivFile = ivInput.files[0];
|
||||
|
||||
if (!encryptedFile || !keyFile || !ivFile) {
|
||||
alert("Please select the encrypted file, key, and IV.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Read the key and IV as JSON
|
||||
const keyData = await keyFile.text();
|
||||
const ivData = await ivFile.text();
|
||||
|
||||
// Convert the JSON data to JavaScript objects
|
||||
const keyObj = JSON.parse(keyData);
|
||||
const iv = JSON.parse(ivData);
|
||||
|
||||
console.log('iv: ', new Uint8Array(iv))
|
||||
|
||||
// const importAlgorithm = {
|
||||
// name: "AES-GCM",
|
||||
// namedCurve: "P-256", // Adjust this curve based on your JWK.
|
||||
// }
|
||||
|
||||
|
||||
const algorithmName="AES-GCM";
|
||||
// const algorithmName="AES-CBC";
|
||||
|
||||
// const importAlgorithm = {
|
||||
// name: "AES-GCM"
|
||||
// };
|
||||
|
||||
const importAlgorithm = {
|
||||
name: algorithmName
|
||||
};
|
||||
|
||||
// const ivSize=12
|
||||
const ivSize=16
|
||||
|
||||
|
||||
const keyUsage = ["encrypt","decrypt"];
|
||||
|
||||
const key = await crypto.subtle.importKey("jwk", keyObj, importAlgorithm, false, keyUsage)
|
||||
|
||||
// 1 mb( size while encrypting + 12 bytes(iv size) )
|
||||
const chunkSize= (1024*1024)+ivSize
|
||||
|
||||
|
||||
const reader = new FileReader();
|
||||
const fileData = [];
|
||||
let offset = 0;
|
||||
|
||||
reader.onload = async function () {
|
||||
console.log('chunk loaded')
|
||||
const chunk = new Uint8Array(reader.result);
|
||||
const decryptedChunk = await window.crypto.subtle.decrypt(
|
||||
{ name: algorithmName, iv: new Uint8Array(ivSize) },
|
||||
key,
|
||||
chunk
|
||||
);
|
||||
fileData.push(decryptedChunk);
|
||||
offset += chunk.length;
|
||||
|
||||
if (offset < encryptedFile.size) {
|
||||
readSlice(offset);
|
||||
} else {
|
||||
// All chunks are encrypted; combine them and provide a download link.
|
||||
const decryptedData = new Blob(fileData, { type: encryptedFile.type });
|
||||
const url = URL.createObjectURL(decryptedData);
|
||||
const downloadLink = document.getElementById("downloadLink");
|
||||
downloadLink.href = url;
|
||||
downloadLink.download="someting.dec"
|
||||
downloadLink.style.display = "block";
|
||||
downloadLink.click()
|
||||
console.log('finished')
|
||||
}
|
||||
};
|
||||
|
||||
function readSlice(offset) {
|
||||
const slice = encryptedFile.slice(offset, offset + chunkSize);
|
||||
reader.readAsArrayBuffer(slice);
|
||||
}
|
||||
|
||||
readSlice(0);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// // Read the encrypted file
|
||||
// const encryptedData = await encryptedFile.arrayBuffer();
|
||||
|
||||
// // Decrypt the file using the Web Crypto API
|
||||
// try {
|
||||
// const decryptedData = await window.crypto.subtle.decrypt(
|
||||
// {
|
||||
// name: "AES-GCM",
|
||||
// iv : new Uint8Array(12)
|
||||
// },
|
||||
// key,
|
||||
// encryptedData
|
||||
// );
|
||||
|
||||
// // Create a Blob from the decrypted data
|
||||
// const decryptedBlob = new Blob([decryptedData]);
|
||||
|
||||
// // Create a download link for the decrypted file
|
||||
// const downloadLink = document.getElementById("downloadLink");
|
||||
// downloadLink.href = URL.createObjectURL(decryptedBlob);
|
||||
// downloadLink.download = "decrypted_file.txt"; // Set the desired file name
|
||||
// downloadLink.style.display = "block";
|
||||
// } catch (error) {
|
||||
// console.error("Decryption error:", error);
|
||||
// alert("Decryption failed. Please check the key and IV.");
|
||||
// }
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
53
joplin notion extension/Web Development/Extras/FreeBSD.md
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
FreeBSD
|
||||
|
||||
- fastest bandwidth I've had, beats Linux 2x over
|
||||
- no hugely fragmented distro bullshit
|
||||
- amazing networking stack, small, clean codebase, clean base system that gets stable updates, but the packages are updated much more often
|
||||
freebsd has the most readable kernel code I have ever seen
|
||||
- So, on FreeBSD you have a base system, everything except user-installed stuff basically. The stuff you install using the package manager does not touch that base system, the base system only gets updated when you update from a release to another. But it's not like Debian, so stuff you install using pkg, the package manager, will get rolling updates.
|
||||
the result is that you can't do anything with your packages that would make your system unbootable
|
||||
you could remove every package on your system and still have a functioning base
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
Markdown preview rendering
|
||||
|
||||
- https://docusaurus.io/
|
||||
install using
|
||||
`npx create-docusaurus@latest my-website classic`
|
||||
Then run it by
|
||||
`cd my-website`
|
||||
`npx docusaurus start`
|
||||
or
|
||||
```bash
|
||||
npm init docusaurus@latest my-website classic
|
||||
cd my-website
|
||||
npm run start
|
||||
```
|
||||
docusarous source code with node_modules
|
||||
docusaurus_bkp.7z https://files.catbox.moe/ibwmte.7z
|
||||
https://www.mediafire.com/file/9clkafkf7vbxgoj/docusaurus_bkp.7z/file
|
||||
docusaurus_preview.mp4 https://small.fileditchstuff.me/s6/mEZTgPTjZwvecEmOfAD.mp4
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
Media Hosting
|
||||
|
||||
- https://www.reddit.com/r/webdev/comments/u7o4iw/any_good_directlink_video_hosting_platforms/
|
||||
|
||||
|
||||
[Any good direct-link video hosting platforms r_webdev.pdf](../../../_resources/Any%20good%20direct-link%20video%20hosting%20platforms%20r_web.pdf)
|
||||
https://github.com/FahadBinHussain/awesome-file-hosts
|
||||
[awesome-file-hosts-main.zip](../../../_resources/awesome-file-hosts-main.zip)
|
||||
- https://nafanz.github.io/
|
||||
[Spreadsheet (16_10_2026 9:09:24 pm).html](../../../_resources/Spreadsheet%20%2816_10_2026%209:09:24%20pm%29.html)
|
||||
|
||||
- https://transfer.sh/
|
||||
- https://www.youtube.com/watch?v=c_arQ-6ElYI : stealing storage from discord
|
||||
https://www.youtube.com/watch?v=QiGKrBDqmKg : from telegram
|
||||
https://disboxapp.github.io/web/
|
||||
https://github.com/devdetour/TelegramFUSE
|
||||
Stealing Storage from Telegram.mp4 https://files.catbox.moe/3esww5.mp4
|
||||
Stealing Storage from Discord.mp4 https://files.catbox.moe/hlqhtk.mp4
|
||||
[TelegramFUSE-main.zip](../../../_resources/TelegramFUSE-main.zip)
|
||||
|
||||
|
||||
- https://app.skiff.com/drive/dashboard : skiff drive
|
||||
- https://www.playbook.com/ : 100GB free
|
||||
- https://fileditch.com/ : 15gb per file peragema storage
|
||||
similary akirabox(30 days after last download) and filester
|
||||
- https://pomf2.lain.la/ : 1gb per file peragema storage
|
||||
https://pone.rs/ : 1gb permanent
|
||||
https://host.hosti.in/ : 20 gb permanent (well not that reliable)
|
||||
https://qu.ax/aIEmt : 256 mb max
|
||||
https://leopard.hosting.pecon.us : 100mb, ddl, no api but maybe can be reverse engineered
|
||||
https://pillows.su/ : for only audio, max is 200mb
|
||||
https://filejump.com/ : 5gb, webdav
|
||||
- https://psitransfer.imagisphe.re/ : 1 week max temp storage
|
||||
https://nowtransfer.de/ : same but for 8 weeks(same ui too)
|
||||
these 2 using this https://github.com/psi-4ward/psitransfer
|
||||
storage.to, : 1 week max, no direct ddl
|
||||
https://buzzheavier.com/ : 8 days, do provide direct links
|
||||
pixeldrain (6gb/day, 60 days limit)
|
||||
https://www.files.dp.ua/, https://dropmefiles.net : 14 days max, wait for download no ddl
|
||||
https://www.tempsend.com/ : 1 week
|
||||
https://www.udrop.com : atleast a week, no ddl access, 100 gb max storage for account
|
||||
https://patchy.moe/ : 4gb file, 14 days
|
||||
|
||||
|
||||
|
||||
https://savedly.net : 7 days
|
||||
- https://hypeshare.io/ : 7 days, 100 downloads max
|
||||
https://1cloudfile.com/ : 20 days, no ddl link
|
||||
https://ufile.io/ : 30 days, no api or ddl link
|
||||
https://datanodes.to/ : 5 days, 3gb / file, no ddl
|
||||
https://spacebyte.in : 25gb, indian (shit , getiing breaking in between, maybe chunk non resume bs)
|
||||
- sync
|
||||

|
||||
- https://bunkr.site/faq : 30 days 2gb/file temp storage
|
||||
- minio : https://www.stackhero.io/en/services/MinIO/pricing, s3 compatible, trial of 2 months but no credit card required
|
||||
- nextcloud
|
||||
https://github.com/thetuxinator/nextcloud_providers
|
||||
https://help.nextcloud.com/t/a-list-of-hosters/193327
|
||||
https://nch.pl/login : 15gb free
|
||||
https://cloud.magdeburg.jetzt/ : 5gb free
|
||||
https://my.adminforge.d : 3gb free
|
||||
- https://chomikuj.pl : unlimited, cons : only in polish,limited quota of 50 mb when not logged in
|
||||
(thjis is unreliable and even for downloading original account is requied so only to be used when to transsfer or temp backup of files)
|
||||
|
||||
video:
|
||||
https://cloudinary.com :
|
||||
|
||||
Upload API - Hourly requests : Unlimited
|
||||
Admin API - Hourly requests : 500
|
||||
Maximum number of users
|
||||
3
|
||||
Maximum number of product environments
|
||||
1
|
||||
Maximum image file size
|
||||
10 MB
|
||||
Maximum video file size
|
||||
100 MB
|
||||
Maximum online image manipulation size
|
||||
100 MB
|
||||
Maximum raw file size
|
||||
10 MB
|
||||
Maximum image megapixels
|
||||
25 MP
|
||||
Maximum total number of megapixels in all frames
|
||||
50 MP
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
Mirrors
|
||||
|
||||
1. Aliucord,cutTheCord,vendetta, lightcord(desktop) : Discord mirror
|
||||
104
joplin notion extension/Web Development/Extras/Open source.md
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
- https://www.tecmint.com/free-open-source-cloud-storage-tools-for-linux/
|
||||
-
|
||||

|
||||
- 
|
||||
|
||||
-https://gitly.org/ : minimal github.com. cant host pages, dont have any ci/cd functionality
|
||||
|
||||
- https://www.shuttle.rs : rust backend hosting paltform
|
||||
|
||||
|
||||
|
||||
- https://pixelfed.org/servers : pixelfed (decentralized image sharing)
|
||||
|
||||
- Mountain duck sync
|
||||
- https://news.itsfoss.com/moosync/ : Moosync music player is an interesting cross-platform app for your local collection and streaming music.
|
||||
- Pinephone : open source hardware phone
|
||||
- https://github.com/makeplane/plane : Open Source JIRA, Linear and Height Alternative. Plane helps you track your issues, epics, and product roadmaps in the simplest way possible.
|
||||
- GitHub - notable/notable: markdown note taking app similar to oplin with no mobile client
|
||||
- https://f-droid.org/en/packages/org.schabi.newpipe/ : newpipe, youtube open source client
|
||||
- animepipe : like newpipe but can watch live too
|
||||
https://piped.kavin.rocks/ : web client
|
||||
https://github.com/TeamPiped/Piped/wiki/Instances
|
||||
[Instances · TeamPiped_Piped Wiki · GitHub (11_10_2023 1_36_12 AM).html](../../../_resources/Instances%20·%20TeamPiped_Piped%20Wiki%20·%20GitHub%20%2811_10_2.html)
|
||||
- https://itsfoss.com/open-source-password-managers/
|
||||
- https://github.com/vfsfitvnm/ViMusic : client of yt music
|
||||
- https://github.com/RobinLinus/snapdrop : file sharing LAN
|
||||
- https://medevel.com/19-lan-file-transfer-file-sharing/
|
||||
- Nuclear music player : can download, fetch lyrics from various services. Electron and heavy
|
||||
- mpv music player : to directly play some individual files. a cli tool
|
||||
- jami : communication app : https://jami.net/
|
||||
- https://news.itsfoss.com/celeste/ : celeste a open source file sync GUI client in rust
|
||||
- https://news.itsfoss.com/ardour-8-2-release/ : for Digital Music Creators
|
||||
- Cmus, qmmp (consoles) : music player
|
||||
- gmusicbrowser , quodlibet(gtk) : music player for linux
|
||||
- https://news.itsfoss.com/exciting-apps-2023/ : 8 Exciting Open Source Apps Linux Users Loved Exploring in 2023
|
||||
- https://news.itsfoss.com/xplorer/ : xplorer
|
||||
- https://news.itsfoss.com/atom-creators-zed-open-source/ : zed(code editor)
|
||||
- https://hoppscotch.io/ : postman alternative
|
||||
https://www.reddit.com/r/selfhosted/comments/152ew7v/good_alternative_to_postman/
|
||||
https://github.com/usebruno/bruno
|
||||
https://github.com/usebruno/bruno/pull/2755/files : bruno with raw file upload
|
||||
https://github.com/flawiddsouza/Restfox : web client
|
||||
thunderclient vs code extension altenative : flashpost, echoapi
|
||||
[bruno-main.zip](../../../_resources/bruno-main.zip)
|
||||
https://github.com/stepci/awesome-api-clients
|
||||
[awesome-api-clients-main.zip](../../../_resources/awesome-api-clients-main.zip)
|
||||
|
||||
|
||||
```txt
|
||||
|
||||
https://firecamp.dev/
|
||||
Restfox https://restfox.dev/
|
||||
|
||||
bruno https://github.com/usebruno/bruno
|
||||
|
||||
Hoppscotch https://hoppscotch.io/
|
||||
|
||||
Hit https://hit.yolo42.com/
|
||||
|
||||
HTTP Client https://www.jetbrains.com/help/idea/http-client-in-product-code-editor.html
|
||||
|
||||
Hurl https://hurl.dev
|
||||
|
||||
Kreya https://kreya.app
|
||||
|
||||
Milkman https://github.com/warmuuh/milkman
|
||||
|
||||
Nap https://github.com/davesheldon/nap
|
||||
|
||||
Paw https://paw.cloud
|
||||
|
||||
restclient.el https://github.com/pashky/restclient.el
|
||||
|
||||
REST Client https://github.com/Huachao/vscode-restclient
|
||||
|
||||
Socketfox https://socketfox.dev
|
||||
|
||||
Step CI https://stepci.com
|
||||
|
||||
vim-http-client https://github.com/aquach/vim-http-client
|
||||
|
||||
vscode-restclient https://github.com/Huachao/vscode-restclient
|
||||
|
||||
verb https://github.com/federicotdn/verb
|
||||
|
||||
rest client: https://addons.mozilla.org/en-US/firefox/addon/restclient/
|
||||
|
||||
httpie: https://httpie.io/
|
||||
|
||||
httprepl : https://devblogs.microsoft.com/dotnet/httprepl-a-command-line-tool-for-interacting-with-restful-http-services/
|
||||
|
||||
API Dash - https://github.com/foss42/apidash
|
||||
|
||||
Pororoca - https://github.com/alexandrehtrb/Pororoca supports HTTP/2 and HTTP/3, full compatibility with Postman collections and environments
|
||||
|
||||
Gist with updates https://gist.github.com/sangelxyz/f73b1f7581318979275322dc13094e19
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
103
joplin notion extension/Web Development/Extras/Privacy.md
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
Privacy
|
||||
|
||||
|
||||
- Quotes
|
||||
https://yourstory.com/2017/06/edward-snowden-quotes-privacy
|
||||
|
||||
|
||||
[Edward Snowden's quotes on the importance of privacy (11_2_2023 12_55_02 PM).html](../../../_resources/Edward%20Snowden_s%20quotes%20on%20the%20importance%20of%20priva.html)
|
||||
|
||||
|
||||
1. Arguing that you don't care about the right to privacy because you have nothing to hide, is no different than saying you don't care about free speech because you have nothing to say.
|
||||
2. "Sometimes the scandal is not what law was broken, but what the law allows."
|
||||
3. It's crazy how "they're just trying to make money" is considered a proper justification for anything corporations do. I also don't see how "spying on kids" is any less creepy than spying on people.
|
||||
4. I need privacy, not because my actions are questionable, but because your judgment and intentions are.
|
||||
|
||||
|
||||
|
||||
|
||||
- Govt ID verification
|
||||
- Comments
|
||||
|
||||
|
||||
I personally hate this. Why should my ID be on 150 services, each with their own servers and security levels?
|
||||
|
||||
It's not safe. There are other ways to verify contact details, I don't want to upload my ID to every service.
|
||||
|
||||
I would promptly leave if I'm asked to do this.
|
||||
|
||||
It's not private, it's not secure, it's not needed.
|
||||
|
||||
Most of the spam messages come from @gmail and @onmicrosoft domains so let's not kid ourselves that this will help in any meaningful way in combating spam.
|
||||
|
||||
|
||||
|
||||
As someone who works for an MSP that has several governmental clients, I can assure you with confidence that those registrars cut corners somewhere, and that PII is stored in some form. Logs, “anonymized” analytics, backups, replication DR, etc.
|
||||
|
||||
This is a problem I complain constantly about, but my clients always shut me down for being “overly paranoid.”
|
||||
|
||||
The best way to prevent data leaks is to have never had the data in the first place.
|
||||
|
||||
|
||||
|
||||
- Aadhar card india
|
||||
In india we need 'aadhar card' to buy a sim which is a national id card which have information such as photo,name,address and biometrics. Also biometrics verification needed to buy sim
|
||||
|
||||
India's Aadhar database isnt secure and is hacked before
|
||||
|
||||
So by giving phone numbes they can cross check details with leaked aadhar card details and get our address and biometric details too
|
||||
|
||||
|
||||
- Importance of VPN
|
||||
1. Hide domain address from ISP
|
||||
2. Access to geoblock content and evade censorship
|
||||
3. Spoofing IP to bypass restrictions when site use IP to ban users or limit them
|
||||
4. Even when we use https there is a chance of MITM(Man in the Middle) attack which is in between device and website so https would be useless
|
||||
5. Some countries (such as India) block the raw.githubusercontent.com domain, which is where some of our files are hosted on
|
||||
6. 
|
||||
|
||||
|
||||
- Privacy orineted setings or apps
|
||||
https://privacy.sexy/
|
||||
https://github.com/imribiy/useful-regs-bats
|
||||
https://github.com/imribiy/group-policy-library
|
||||
- https://www.makeuseof.com/tag/how-to-delete-personal-data-public-record-websites/
|
||||
-
|
||||
- https://anonymousplanet.org/\
|
||||
https://anonymousplanet.org/guide.html
|
||||
https://files.sdrive.app/b6e2b6cd-897c-4bbb-b102-1c710e37dfd1.pdf
|
||||
https://files.sdrive.app/3eff131c-bdc9-4655-9c60-7fb00927af6c.html
|
||||
The Hitchhiker’s Guide to Online Anonymity The Hitchhiker’s Guide to Online Anonymity.pdf
|
||||
https://files.catbox.moe/imdlhy.pdf
|
||||
The Hitchhiker’s Guide to Online Anonymity _ The Hitchhiker’s Guide to Online Anonymity (6_6_2024 5_43_59 am).html
|
||||
https://files.catbox.moe/zzzuvz.html
|
||||
|
||||
- https://reports.exodus-privacy.eu.org/en/ : to check if a certain app has facebook trackers or not
|
||||
- https://stealths.net/ : to get burner credit card
|
||||
|
||||
- Whonix is a debian based operating system and it's built on security, your IP is hidden because of the technique of isolation. It's built on two major programs:
|
||||
|
||||
System,
|
||||
Gateway
|
||||
The gateway acts as a middleman and it forces every request reaching your system into the Tor network making you untrackable
|
||||
- People say that 'no one is interested to spy on you loser' but would u rather open a bathroom door if your room mate say 'no need to close bcz I won't bother u and I don't wanna see u shit'
|
||||
Reason is not about if anyone spies it's more about not letting us keep profiting from data and have peace of mind so that we live with dignity
|
||||
- russia :
|
||||
Q: when trying to connect to vpn?
|
||||
A: It blocks responses from the server
|
||||
so there's literally nothing
|
||||
from inside you don't even get a message, it's just as if the server didn't exist
|
||||
Q : can u connect to tor without bridge?
|
||||
A : no we need to use bridge for that
|
||||
what r banned in russia
|
||||
political stuff, twitter, anything facebook, some media
|
||||
- dangerous stuffs
|
||||
- https://scholar.harvard.edu/files/mickens/files/thisworldofours.pdf
|
||||
- https://xkcd.com/538/
|
||||
- discord phone number thing
|
||||
https://support.discord.com/hc/en-us/community/posts/1500001194821-Discord-now-requires-your-personal-phone-number-to-use-Discord-after-account-is-locked-Something-s-going-on-here-error
|
||||
|
||||
|
||||
|
||||
privacy measures with discord
|
||||
https://discuss.privacyguides.net/t/strategies-how-to-use-discord-or-any-service-that-requires-an-account-more-privately/17502
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
caddy
|
||||
|
||||
either install go binary and place it where root user can access or use your package manager to install
|
||||
|
||||
and for domains which are not public use this TLD
|
||||
`.local`, `.internal`, `.localhost` and make to sure to register them like this
|
||||
|
||||
```sh
|
||||
sudo nano /etc/hosts
|
||||
```
|
||||
then
|
||||
add this
|
||||
`127.0.0.1 exampler1267.internal`
|
||||
|
||||
Caddyfile example
|
||||
|
||||
```txt
|
||||
localhost:3009 {
|
||||
respond "Hello, world!"
|
||||
}
|
||||
|
||||
|
||||
# :8007 {
|
||||
# bind 0.0.0.0
|
||||
# tls internal
|
||||
# reverse_proxy :8008
|
||||
# }
|
||||
|
||||
|
||||
https://localhost:8007 {
|
||||
bind 0.0.0.0
|
||||
tls internal
|
||||
reverse_proxy :8008
|
||||
}
|
||||
|
||||
|
||||
https://192.168.29.234:8007 {
|
||||
bind 0.0.0.0
|
||||
tls internal
|
||||
reverse_proxy :8008
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
use `caddy start` and `caddy stop` to start and end process
|
||||
|
|
@ -0,0 +1,337 @@
|
|||
resource
|
||||
https://github.com/spantaleev/matrix-docker-ansible-deploy
|
||||
|
||||
matrix homeserver
|
||||
|
||||
some servers
|
||||
- synapse : standard one and feature rich but heavy
|
||||
|
||||
lightweight ones
|
||||
https://git.telodendria.org/jakubgencur/Telodendria, conduit,dendrite and https://github.com/heusalagroup/hghs, https://github.com/matrix-construct/tuwunel
|
||||
|
||||
|
||||
trying tuwunel
|
||||
1. download release https://github.com/matrix-construct/tuwunel/releases/download/v1.5.1/v1.5.1-release-all-x86_64-v3-linux-gnu-tuwunel.zst
|
||||
2. executing it will work but first needed to be configured
|
||||
3. create a toml file say `config.toml` and use example from https://matrix-construct.github.io/tuwunel/configuration/examples.html#example-configuration (it acts as template). or [config.toml](../../../../_resources/config.toml)
|
||||
```toml
|
||||
|
||||
[global]
|
||||
|
||||
# The server_name is the pretty name of this server. It is used as a
|
||||
# suffix for user and room IDs/aliases.
|
||||
#
|
||||
# See the docs for reverse proxying and delegation:
|
||||
# https://tuwunel.chat/deploying/generic.html#setting-up-the-reverse-proxy
|
||||
#
|
||||
# Also see the `[global.well_known]` config section at the very bottom.
|
||||
#
|
||||
# Examples of delegation:
|
||||
# - https://matrix.org/.well-known/matrix/server
|
||||
# - https://matrix.org/.well-known/matrix/client
|
||||
#
|
||||
# YOU NEED TO EDIT THIS. THIS CANNOT BE CHANGED AFTER WITHOUT A DATABASE
|
||||
# WIPE.
|
||||
#
|
||||
# example: "girlboss.ceo"
|
||||
#
|
||||
server_name = "muty.org"
|
||||
|
||||
# This is the only directory where tuwunel will save its data, including
|
||||
# media. Note: this was previously "/var/lib/matrix-conduit".
|
||||
#
|
||||
database_path = "database"
|
||||
|
||||
allow_registration = true
|
||||
|
||||
# Enabling this setting opens registration to anyone without restrictions.
|
||||
# This makes your server vulnerable to abuse
|
||||
#
|
||||
yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse = true
|
||||
|
||||
# by adding 0.0.0.0 it will not only be available for localhost but for devices sharing same wifi too
|
||||
address = ["127.0.0.1", "::1","0.0.0.0"]
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
synapse
|
||||
https://element-hq.github.io/synapse/latest/setup/installation.html#installing-as-a-python-module-from-pypi
|
||||
|
||||
pip way
|
||||
after creating a folder and cd to it
|
||||
|
||||
```sh
|
||||
python3 -m venv env # to create venv
|
||||
source env/bin/activate # to activate it
|
||||
pip install --upgrade pip
|
||||
pip install --upgrade setuptools
|
||||
pip install matrix-synapse
|
||||
```
|
||||
|
||||
configuration
|
||||
`python -m synapse.app.homeserver \
|
||||
--server-name my.domain.name \
|
||||
--config-path homeserver.yaml \
|
||||
--generate-config \
|
||||
--report-stats=[yes|no]`
|
||||
|
||||
starting it
|
||||
`synctl start`
|
||||
or for non daemon
|
||||
`python3 -m synapse.app.homeserver -c homeserver.yaml`
|
||||
|
||||
more configuration
|
||||
```yml
|
||||
enable_registration: true
|
||||
enable_registration_without_verification: true
|
||||
url_preview_enabled: true
|
||||
url_preview_ip_range_blacklist: null
|
||||
```
|
||||
|
||||
|
||||
using postgresql instead of sqlite for production
|
||||
https://element-hq.github.io/synapse/latest/postgres.html#porting-from-sqlite
|
||||

|
||||
|
||||
1. Make sure to install `psycopg2` by `source env/bin/activate && pip install psycopg2-binary`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
**connecting with ngrok**
|
||||
|
||||
The error you're seeing—"homeserver configuration found with <url> is unusable"—typically comes from **Element** (or another Matrix client) when it discovers your homeserver's configuration (via `.well-known` or direct probing) but decides the setup is invalid or unreachable for some reason.
|
||||
|
||||
This is **very common** when using **ngrok** to expose a local Synapse server (especially on localhost:8008), because ngrok creates a temporary HTTPS URL, but several things break federation/client discovery.
|
||||
|
||||
### Most likely causes with ngrok
|
||||
1. **Your `server_name`** in `homeserver.yaml` is still set to something like `localhost`, `127.0.0.1`, or your local machine name (not the ngrok URL).
|
||||
- Synapse **must** know its public identity → `server_name: your-ngrok-subdomain.ngrok-free.app` (or whatever your ngrok URL is without https://).
|
||||
- Clients expect the homeserver to present itself consistently under that name.
|
||||
|
||||
2. **No `.well-known/matrix/server`** and/or `.well-known/matrix/client`** delegation set up.
|
||||
- Modern clients (especially Element) strongly prefer or require **delegation** via these files when the base URL ≠ server_name.
|
||||
- With ngrok you almost always need them.
|
||||
|
||||
3. **Ngrok free tier limitations** — the random/free URLs often cause strict clients to reject the certificate or see the setup as "unusable" because:
|
||||
- The domain doesn't match expectations
|
||||
- No proper TLS setup or mixed HTTP/HTTPS probing
|
||||
- Ngrok injects a page/captchas sometimes → breaks /.well-known requests
|
||||
|
||||
4. **You're entering the wrong URL in the client**:
|
||||
- Don't enter `http://localhost:8008`
|
||||
- Don't enter `https://xxxx.ngrok-free.app:8008` (ngrok already forwards to 8008)
|
||||
- Usually just enter `https://xxxx.ngrok-free.app` (or your custom ngrok domain)
|
||||
|
||||
### Quick fix steps (most reliable for ngrok)
|
||||
|
||||
1. **Stop Synapse**, edit `homeserver.yaml`:
|
||||
```yaml
|
||||
server_name: "abcd1234.ngrok-free.app" # ← use your ACTUAL ngrok URL here (no https://, no port)
|
||||
|
||||
# If you want federation later (optional but recommended)
|
||||
federation_domain_whitelist: [] # or leave commented
|
||||
|
||||
# Make sure these are NOT forcing http or weird ports
|
||||
public_baseurl: https://abcd1234.ngrok-free.app/ # optional but helps
|
||||
```
|
||||
|
||||
→ Restart Synapse
|
||||
|
||||
2. **Set up .well-known delegation** (this is usually what fixes the "unusable" error):
|
||||
|
||||
Create a simple static web server (or use Python's built-in one) on port 80 or 443 if you can, but since you're using ngrok for 8008, the easiest is:
|
||||
|
||||
- Run a tiny HTTP server in a separate terminal (in a new folder):
|
||||
```bash
|
||||
mkdir well-known
|
||||
cd well-known
|
||||
mkdir -p .well-known/matrix
|
||||
```
|
||||
|
||||
Create two files:
|
||||
|
||||
`.well-known/matrix/server`:
|
||||
```json
|
||||
{
|
||||
"m.server": "abcd1234.ngrok-free.app:443"
|
||||
}
|
||||
```
|
||||
|
||||
`.well-known/matrix/client`:
|
||||
```json
|
||||
{
|
||||
"m.homeserver": {
|
||||
"base_url": "https://abcd1234.ngrok-free.app"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- Start a simple server in that folder:
|
||||
```bash
|
||||
python3 -m http.server 8080
|
||||
```
|
||||
|
||||
- Run a **second ngrok** tunnel just for this well-known:
|
||||
```bash
|
||||
ngrok http 8080
|
||||
```
|
||||
|
||||
→ Get a new ngrok URL, e.g. `https://abcd-wellknown.ngrok-free.app`
|
||||
|
||||
- Then in your **main** homeserver.yaml add/change:
|
||||
```yaml
|
||||
serve_server_wellknown: false # optional
|
||||
```
|
||||
|
||||
But actually tell clients to use the well-known domain as the homeserver URL.
|
||||
|
||||
Better: use your main ngrok URL as server_name, and serve the .well-known files via Synapse itself (add to homeserver.yaml):
|
||||
```yaml
|
||||
additional_wellknown_roots:
|
||||
- path: /.well-known/matrix/server
|
||||
content: '{"m.server": "your-ngrok-url:443"}'
|
||||
- path: /.well-known/matrix/client
|
||||
content: '{"m.homeserver": {"base_url": "https://your-ngrok-url"}}'
|
||||
```
|
||||
|
||||
Restart Synapse → it will serve them directly.
|
||||
|
||||
3. **In Element** (web/desktop/mobile):
|
||||
- Custom server / Edit → enter exactly `https://your-ngrok-url` (no port, no /)
|
||||
- It should discover the config and say something like "Homeserver configuration found with https://your-ngrok-url"
|
||||
- If it still says unusable → open browser dev tools (F12) → Network tab → look what request to `/_matrix/client/versions` or `/.well-known` fails and why (404, 502, cert error, etc.)
|
||||
|
||||
### Even easier alternatives if ngrok keeps fighting you
|
||||
- Use a free static tunnel like **bore.pub**, **pinggy.io**, or **localhost.run** (sometimes behave better with Matrix)
|
||||
- Get a cheap domain + Cloudflare Tunnel (zero trust) — much more reliable for Synapse
|
||||
- Use Tailscale / Headscale + funnel — exposes localhost securely without public URL hassle
|
||||
|
||||
Test first with `curl https://your-ngrok-url/_matrix/client/versions` — should return JSON with `"versions": [...]`.
|
||||
|
||||
If you share:
|
||||
- Your exact `server_name:` line
|
||||
- The full ngrok URL you're using
|
||||
- What exactly you enter in Element
|
||||
- The **exact** error message (including the <url> part)
|
||||
|
||||
I can narrow it down further!
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### for converting to https for LAN IP
|
||||
|
||||
resource : https://medium.com/@antelle/how-to-generate-a-self-signed-ssl-certificate-for-an-ip-address-f0dd8dddf754
|
||||

|
||||
**Self sign certificate way**
|
||||
- create the following file named `openssl.cnf`. `192.168.1.50` is LAN IP
|
||||
```
|
||||
[ req ]
|
||||
default_bits = 2048
|
||||
distinguished_name = req_distinguished_name
|
||||
req_extensions = req_ext
|
||||
prompt = no
|
||||
|
||||
[ req_distinguished_name ]
|
||||
C = US
|
||||
ST = State
|
||||
L = City
|
||||
O = Local
|
||||
CN = 127.0.0.1
|
||||
|
||||
[ req_ext ]
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[ alt_names ]
|
||||
IP.1 = 127.0.0.1
|
||||
DNS.1 = localhost
|
||||
IP.2 = 192.168.1.50
|
||||
|
||||
```
|
||||
- now using this configuration, generate certificate and private key
|
||||
`openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt -config openssl.cnf -extensions req_ext`
|
||||
- not finallly in `homeserver.yaml` add these cetificates and enable tls
|
||||
```yaml
|
||||
server_name: "muta.org"
|
||||
pid_file: /home/hpmi/Downloads/executables/synapse/homeserver.pid
|
||||
|
||||
# 1. Add these two lines globally to define your certificate paths
|
||||
tls_certificate_path: "/home/hpmi/Downloads/executables/synapse/server.crt"
|
||||
tls_private_key_path: "/home/hpmi/Downloads/executables/synapse/server.key"
|
||||
|
||||
listeners:
|
||||
- bind_addresses:
|
||||
- ::1
|
||||
- 0.0.0.0
|
||||
port: 8008
|
||||
resources:
|
||||
- compress: false
|
||||
names:
|
||||
- client
|
||||
- federation
|
||||
tls: true # 2. Change this from false to true
|
||||
type: http
|
||||
x_forwarded: true
|
||||
```
|
||||
|
||||
- Now trust these certificates in client. in browser or maybe some apps there might be prompt to trust them so do that. in browser open the server LAN IP(not the client one) in tab and select 'accpet risk and continue'. in case of desktop like linux add them like this. add that crt file in this location `/usr/local/share/ca-certificates/` and then run command for updating `sudo update-ca-certificates`
|
||||
|
||||
for a full ca one use
|
||||
`openssl req -x509 -newkey rsa:4048 -keyout key.pem -out cert.pem -days 365 -nodes -subj "/CN=localhost" -addext "basicConstraints=critical,CA:TRUE"`
|
||||
|
||||
with https there can be issues with client which give no proper option to allow self signed certifciates so best way is to use both and use http where it can be used
|
||||
in `homeserver.yaml`
|
||||
```yaml
|
||||
listeners:
|
||||
# HTTPS
|
||||
- port: 8448
|
||||
bind_addresses:
|
||||
- "0.0.0.0"
|
||||
- "::1"
|
||||
type: http
|
||||
tls: true
|
||||
x_forwarded: false
|
||||
resources:
|
||||
- names:
|
||||
- client
|
||||
- federation
|
||||
compress: false
|
||||
|
||||
# HTTP
|
||||
- port: 8008
|
||||
bind_addresses:
|
||||
- "0.0.0.0"
|
||||
- "::1"
|
||||
type: http
|
||||
tls: false
|
||||
x_forwarded: false
|
||||
resources:
|
||||
- names:
|
||||
- client
|
||||
- federation
|
||||
compress: false
|
||||
```
|
||||
|
||||
|
||||
Client
|
||||
|
||||
Nheko
|
||||
|
||||
for managing multiple accounts use profile
|
||||
|
||||
|
||||
`flatpak run im.nheko.Nheko -p default` or `flatpak run im.nheko.Nheko`
|
||||
if not flatpak and directly installed
|
||||
`nheko -p default`
|
||||
for something other than default
|
||||
`nheko -p work`
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,174 @@
|
|||
spacebar chat
|
||||
also on
|
||||
https://sbar.fyi
|
||||
client on
|
||||
https://git.sovrahi.com/oh64/Fermo
|
||||
|
||||
Date created : 11 feb 2026
|
||||
**Server setup**
|
||||
1. Get the files from https://github.com/spacebarchat/server
|
||||
2. Now make sure to have node, python and psql installed. check version requiremnts on site
|
||||
3. Install all node depedencies with `npm i`
|
||||
4. Setup the postgresql database by creating a database say `spacebar` with query `create database spacebar`
|
||||
5. Create a .env file in root of project and type `postgres://postgres:PASS@localhost:5432/spacebar` here PASS is password. by default password maybe your system one which is used to install program
|
||||
6. Now run `npm run build` to build distribution files and `npm run start` to execute those
|
||||
7. There will be error related to invalid values of configs. In database spacebar many tables will be created. One such is config. So update some values. If using cli then execute following queries
|
||||
```sql
|
||||
update config set value='"http://localhost:3001"' where key='general_serverName';
|
||||
update config set value='"http://localhost:3001/api/v9"' where key='api_endpointPublic';
|
||||
update config set value='"http://localhost:3001"' where key='cdn_endpointPublic';
|
||||
update config set value='"http://localhost:3001"' where key='cdn_endpointPrivate';
|
||||
update config set value='"ws://localhost:3001"' where key='gateway_endpointPublic';
|
||||
```
|
||||
or
|
||||
in .env use
|
||||
```txt
|
||||
DATABASE=postgres://postgres:PASS@localhost:5432/spacebar
|
||||
CONFIG_PATH=config.json
|
||||
STORAGE_LOCATION=/mnt/hdd/files #Optional
|
||||
```
|
||||
|
||||
for more environment variables refer to this
|
||||
https://docs.spacebar.chat/setup/server/configuration/env/
|
||||
now the config.json will be created when using npm run start and then mutate the values too. after mutating values this will be config.json
|
||||
[config.json](../../../../_resources/config.json)
|
||||
|
||||
|
||||
**Client setup**
|
||||
1. after cloning and moving to that directory simply `npm run build` and `npm start` will work
|
||||
2. In order to connect with custom server, add instance like this. here instanced named 'MySpacebar' is added. this file is in `src/webpage/instances.json`
|
||||
```json
|
||||
[
|
||||
{
|
||||
"name": "Spacebar",
|
||||
"description": "The official Spacebar instance.",
|
||||
"image": "https://raw.githubusercontent.com/spacebarchat/spacebarchat/master/branding/png/Spacebar__Icon-Discord.png",
|
||||
"url": "https://spacebar.chat"
|
||||
},
|
||||
{
|
||||
"name": "MySpacebar",
|
||||
"description": "My Own Spacebar instance.",
|
||||
"url": "http://localhost:3001"
|
||||
},
|
||||
{
|
||||
"name": "Fastbar",
|
||||
"description": "The best Spacebar instance with 95% uptime, running under on a NVME drive running with bleeding edge stuff <3",
|
||||
"image": "https://spacebar.greysilly7.xyz/logo.png",
|
||||
"url": "https://greysilly7.xyz",
|
||||
"language": "en",
|
||||
"country": "US",
|
||||
"display": true,
|
||||
"urls": {
|
||||
"wellknown": "https://greysilly7.xyz",
|
||||
"api": "https://api-spacebar.greysilly7.xyz/api",
|
||||
"cdn": "https://cdn-spacebar.greysilly7.xyz",
|
||||
"gateway": "wss://gateway-spacebar.greysilly7.xyz"
|
||||
},
|
||||
"contactInfo": {
|
||||
"discord": "greysilly7",
|
||||
"github": "https://github.com/greysilly7",
|
||||
"email": "greysilly7@gmail.com"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
|
||||
personal bash script to open server, client and scn server
|
||||
|
||||
```sh
|
||||
#!/bin/bash
|
||||
|
||||
SESSION="spacebar_session"
|
||||
|
||||
FIRST_COMMAND='nvm use 24 && cd "/home/hpmi/Videos/imp/github_forks/set2/spacebar/server" && npm run start'
|
||||
# SECOND_COMMAND='nvm use 24 && cd "/home/hpmi/Videos/imp/github_forks/set2/spacebar/spacebar client/Fermi" && npm run start1'
|
||||
SECOND_COMMAND='nvm use 24 && cd "/home/hpmi/Videos/imp/github_forks/set2/spacebar/spacebar client/Fermo" && caddy run --config ./Caddyfile'
|
||||
THIRD_COMMAND='cd "/media/hpmi/Seagate/main/symlinks/selfBot/files" && python3 -m http.server 3003'
|
||||
|
||||
tmux new-session -d -s $SESSION
|
||||
|
||||
#C-m emulates pressing enter key
|
||||
tmux send-keys -t $SESSION:0 "$FIRST_COMMAND" C-m
|
||||
|
||||
#create a new window of index 1 with name 'logs'
|
||||
tmux new-window -t $SESSION:1 -n "client"
|
||||
tmux send-keys -t $SESSION:1 "$SECOND_COMMAND" C-m
|
||||
|
||||
tmux new-window -t $SESSION:2 -n "cdn_serve"
|
||||
tmux send-keys -t $SESSION:2 "$THIRD_COMMAND" C-m
|
||||
|
||||
tmux attach-session -t $SESSION
|
||||
```
|
||||
|
||||
|
||||
|
||||
fermo
|
||||
so fork fermo then `npm build`
|
||||
now for static hosting, make some rewrites
|
||||
|
||||
by caddy
|
||||
```txt
|
||||
http://localhost:8080 {
|
||||
root * "/home/hpmi/Videos/imp/github_forks/set2/spacebar/spacebar client/Fermo/dist/webpage"
|
||||
file_server
|
||||
|
||||
# Fallback rewrites for specific path prefixes
|
||||
rewrite /channels/* /app.html
|
||||
rewrite /invite/* /invite.html
|
||||
rewrite /template/* /template.html
|
||||
|
||||
# Static file routing with a custom 404 fallback
|
||||
try_files {path} {path}/ /404.html
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
nginx
|
||||
```
|
||||
server {
|
||||
listen 80;
|
||||
server_name localhost;
|
||||
|
||||
root /path/to/fermo/dist/webpage;
|
||||
index index.html;
|
||||
|
||||
location /channels/ {
|
||||
rewrite ^ /app.html last;
|
||||
}
|
||||
|
||||
location /invite/ {
|
||||
rewrite ^ /invite.html last;
|
||||
}
|
||||
|
||||
location /template/ {
|
||||
rewrite ^ /template.html last;
|
||||
}
|
||||
|
||||
# Static files and directories
|
||||
location / {
|
||||
try_files $uri $uri/ /404.html;
|
||||
}
|
||||
|
||||
error_page 404 /404.html;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
for spacebarchat ferno pull requests
|
||||
|
||||
You can log in with codeberg or Github or create a full sovrahi account, to send a commit the easiest way is to create a token in the forgejo token and do
|
||||
https://[yourtoken]@git.sovrahi.com/yourfork
|
||||
Then create a pull request
|
||||
|
||||
how to explain it better hmmm
|
||||
you go on https://git.sovrahi.com/oh64/Fermo click on "Fork" then confirm
|
||||
once in your fork copy the link to it (the url should be different)
|
||||
in your account setting, go in https://git.sovrahi.com/user/settings/applications
|
||||
Create a new token need to give it read and write for repository
|
||||
then on your computer (you need git installed) you make a `git clone https://git.sovrahi.com/yoururl` OR this step you can also do git clone `https://[yourtoken]@git.sovrahi.com/yoururl`
|
||||
but if you do it the first way it will ask for the token when you will try to push
|
||||
|
||||
on the fermo repo, on pull request, click on "new pull request" explain your things and create it!
|
||||

|
||||
127
joplin notion extension/Web Development/Extras/Tools/xmpp.md
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
xmpp
|
||||
resources
|
||||
https://www.reddit.com/r/xmpp/comments/cavyiv/good_xmpp_clients_and_servers/
|
||||
|
||||
clients
|
||||
https://xmpp.org/getting-started/
|
||||
one such is https://mov.im/login, conversejs
|
||||
and gajim for windows and linux ie https://github.com/gajim/gajim
|
||||
|
||||
- xmpp providers: https://providers.xmpp.net/provider/07f.de/, https://providers.xmpp.net/provider/chapril.org/ (weird capchas) , https://providers.xmpp.net/provider/movim.eu/ (50 mb max file)
|
||||
https://07f.de/ provides other free services too
|
||||
|
||||
|
||||
dino client
|
||||
https://github.com/dino/dino/
|
||||
after building it,to have different profiles
|
||||
`XDG_DATA_HOME="$HOME/.dino_profiles/work/share" XDG_CONFIG_HOME="$HOME/.dino_profiles/work/config" dino`
|
||||
or
|
||||
`XDG_DATA_HOME="$HOME/.dino_profiles/work/" dino`
|
||||
|
||||
|
||||
**server**
|
||||
|
||||
prosody
|
||||
https://prosody.im/doc/installing_from_source
|
||||
|
||||
first install lua and all the dependecnies
|
||||
`apt install lua5.4 liblua5.4-dev libicu-dev libssl-dev`
|
||||
and also luarocks too
|
||||
|
||||
then more lua dependencies using luarocks
|
||||
to use luarocks directly
|
||||
`luarocks install luaexpat --local --lua-version=5.4`
|
||||
similarly do same for luafilesystem and luaunbound too
|
||||
|
||||
this can be headache too like setting ssl and all that thing so using snikket can help too, only con is more space required and cant be simply used in termux
|
||||
|
||||
**snikket**
|
||||
https://snikket.org/service/quickstart/
|
||||
|
||||
if using podman then add `docker.io/` before images so podman knows to fetch from here
|
||||
and also change the port too by changing `snikket.conf` and adding these lines
|
||||
```txt
|
||||
SNIKKET_TWEAK_HTTP_PORT=5080
|
||||
SNIKKET_TWEAK_HTTPS_PORT=5443
|
||||
|
||||
# The primary domain of your Snikket instance
|
||||
SNIKKET_DOMAIN=snikket.local
|
||||
|
||||
# An email address where the admin can be contacted
|
||||
# (also used to register your Let's Encrypt account to obtain certificates)
|
||||
SNIKKET_ADMIN_EMAIL=admin@localhost
|
||||
|
||||
```
|
||||
|
||||
Also create a `.env` file and
|
||||
```txt
|
||||
SNIKKET_DATA_DIR=/home/hpmi/Downloads/executables/Snikket/data
|
||||
```
|
||||
|
||||
and in compose file make these changes
|
||||
```yml
|
||||
version: "3.3"
|
||||
|
||||
services:
|
||||
snikket_proxy:
|
||||
container_name: snikket-proxy
|
||||
image: docker.io/snikket/snikket-web-proxy:stable
|
||||
env_file: snikket.conf
|
||||
network_mode: host
|
||||
volumes:
|
||||
- ${SNIKKET_DATA_DIR}:/snikket
|
||||
- acme_challenges:/var/www/html/.well-known/acme-challenge
|
||||
restart: "unless-stopped"
|
||||
snikket_certs:
|
||||
container_name: snikket-certs
|
||||
image: docker.io/snikket/snikket-cert-manager:stable
|
||||
network_mode: host
|
||||
env_file: snikket.conf
|
||||
volumes:
|
||||
- ${SNIKKET_DATA_DIR}:/snikket
|
||||
- acme_challenges:/var/www/.well-known/acme-challenge
|
||||
restart: "unless-stopped"
|
||||
snikket_portal:
|
||||
container_name: snikket-portal
|
||||
image: docker.io/snikket/snikket-web-portal:stable
|
||||
network_mode: host
|
||||
env_file: snikket.conf
|
||||
restart: "unless-stopped"
|
||||
|
||||
snikket_server:
|
||||
container_name: snikket
|
||||
image: docker.io/snikket/snikket-server:stable
|
||||
network_mode: host
|
||||
volumes:
|
||||
- ${SNIKKET_DATA_DIR}:/snikket
|
||||
env_file: snikket.conf
|
||||
restart: "unless-stopped"
|
||||
|
||||
volumes:
|
||||
acme_challenges:
|
||||
|
||||
```
|
||||
|
||||
so for localhost, need to generate fake certificates
|
||||
```sh
|
||||
# 1. Create the new folder structure matching the domain
|
||||
mkdir -p /your/custom/path/letsencrypt/live/snikket.local/
|
||||
|
||||
# 2. Generate the certificate with Multi-SAN support
|
||||
openssl req -x509 -newkey rsa:4096 -sha256 -days 3650 -nodes \
|
||||
-keyout /your/custom/path/letsencrypt/live/snikket.local/privkey.pem \
|
||||
-out /your/custom/path/letsencrypt/live/snikket.local/fullchain.pem \
|
||||
-subj "/CN=snikket.local" \
|
||||
-addext "subjectAltName=DNS:snikket.local,DNS:localhost,IP:127.0.0.1,IP:
|
||||
```
|
||||
|
||||
in `/etc/hosts`
|
||||
```txt
|
||||
127.0.0.1 snikket.local share.snikket.local
|
||||
```
|
||||
|
||||
using this will give invite link for admin
|
||||
`docker exec snikket create-invite --admin --group default`
|
||||
|
||||
since port 5443 is used so add that. eg
|
||||
`https://snikket.local:5443/invite/PP46bac4bk0wxHD50RbR7_6G/`
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
adding dns records
|
||||
|
||||
cloudfare
|
||||
|
||||
## by llm
|
||||
Yes, **Cloudflare** allows you to manage DNS records for free, and it's a very popular option for managing DNS due to its reliability and additional features like security, CDN, and DDoS protection. Here’s how it works:
|
||||
|
||||
### Why Cloudflare is a Great Option:
|
||||
|
||||
* **Free DNS Management**: You can add, remove, or modify `A`, `CNAME`, `MX`, and other DNS records without any cost.
|
||||
* **Performance & Security**: Cloudflare offers a **free CDN** (Content Delivery Network) and **DDoS protection**, which can help make your website faster and more secure.
|
||||
* **DNS Propagation**: Changes to DNS records via Cloudflare typically propagate much faster compared to traditional registrars.
|
||||
|
||||
### How to Set Up Cloudflare for Your Subdomain
|
||||
|
||||
Here’s a step-by-step guide to setting up Cloudflare for free:
|
||||
|
||||
#### 1. **Sign Up for Cloudflare**
|
||||
|
||||
* Go to [Cloudflare's website](https://www.cloudflare.com/).
|
||||
* Click on **Sign Up** and create an account using your email and password.
|
||||
|
||||
#### 2. **Add Your Domain to Cloudflare**
|
||||
|
||||
* After logging in, you’ll be prompted to add your domain (e.g., `yourdomain.com`) to Cloudflare.
|
||||
* Enter your **domain name** (without `www`) and click **Add Site**.
|
||||
|
||||
#### 3. **Cloudflare Scans Your Existing DNS Records**
|
||||
|
||||
* Cloudflare will scan your current DNS records (provided by your current registrar) and show you a list of existing DNS records.
|
||||
* Confirm that Cloudflare has detected your records correctly, then click **Continue**.
|
||||
|
||||
#### 4. **Choose a Plan**
|
||||
|
||||
* Cloudflare will ask you to select a plan. For most use cases, the **Free plan** is perfect, as it includes DNS management, DDoS protection, and other basic features.
|
||||
* Choose **Free Plan** and click **Confirm Plan**.
|
||||
|
||||
#### 5. **Update Your Nameservers**
|
||||
|
||||
* Cloudflare will now provide you with two **nameservers** (something like `ns1.cloudflare.com` and `ns2.cloudflare.com`).
|
||||
* Go to your domain registrar (where you bought the domain) and **update your nameservers** to the ones provided by Cloudflare.
|
||||
|
||||
* This change might take some time to propagate (up to 24 hours, but usually faster).
|
||||
|
||||
#### 6. **Add DNS Records for Your Subdomain**
|
||||
|
||||
Once Cloudflare is active on your domain, you can add DNS records for your subdomains:
|
||||
|
||||
* Log in to your Cloudflare dashboard.
|
||||
* Select your domain (`yourdomain.com`).
|
||||
* Go to the **DNS** tab, where you'll manage all your DNS records.
|
||||
|
||||
To create a **subdomain** (e.g., `subdomain.yourdomain.com`):
|
||||
|
||||
1. Click on **Add record**.
|
||||
2. Choose the **Type** of record:
|
||||
|
||||
* **A Record** if you're pointing to an IP address (your VPS IP).
|
||||
* **CNAME Record** if you want the subdomain to point to another domain or subdomain.
|
||||
3. **Fill in the details**:
|
||||
|
||||
* For `A Record`: Set **Name** as `subdomain` (or whatever your subdomain is) and set **IPv4 address** to your VPS’s IP address.
|
||||
* For `CNAME Record`: Set **Name** as `subdomain` and **Target** as the domain you want to point to (e.g., `yourdomain.com`).
|
||||
4. Click **Save**.
|
||||
|
||||
#### 7. **Wait for DNS Propagation**
|
||||
|
||||
It may take some time for DNS changes to propagate, but Cloudflare is usually faster than traditional DNS services. After that, your subdomain (e.g., `subdomain.yourdomain.com`) will point to your VPS or the target domain.
|
||||
|
||||
---
|
||||
|
||||
### Additional Benefits of Using Cloudflare:
|
||||
|
||||
* **SSL/TLS Support**: You can easily set up SSL certificates on your domain and subdomains via Cloudflare for **free**, enabling HTTPS.
|
||||
* **Caching & CDN**: Cloudflare caches static content (images, CSS, JS) on its global CDN, improving site load times.
|
||||
* **Security Features**: Cloudflare offers protections against DDoS attacks, bot traffic, and other malicious activities.
|
||||
|
||||
---
|
||||
|
||||
### Quick Overview:
|
||||
|
||||
1. **Create a Cloudflare Account** and add your domain.
|
||||
2. **Update Nameservers** to Cloudflare’s nameservers at your domain registrar.
|
||||
3. **Add DNS Records** (like `A` or `CNAME`) for your subdomain.
|
||||
4. Cloudflare’s free plan will handle DNS management and more.
|
||||
|
||||
So, yes—**Cloudflare lets you add DNS records for free** and offers additional features that can boost your site's performance and security. Would you like help with any of the specific steps?
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
cli commands for different programming languages
|
||||
- C
|
||||
Requiments : gcc in linux and mingw in windows
|
||||
For build system : meson, cmake,pkg-config
|
||||
configuration file : Makefile
|
||||
```c
|
||||
#include <stdio.h>
|
||||
int main() {
|
||||
// printf() displays the string inside quotation
|
||||
printf("Hello, World!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
- Compiling and running
|
||||
`gcc hello.c -o hello`
|
||||
Additionally to link packages use
|
||||
```
|
||||
gcc `pkg-config --cflags gtk+-3.0` -o main1 main.c `pkg-config --libs gtk+-3.0`
|
||||
```
|
||||
this will compile and create a binary file named `hello`
|
||||
Running it
|
||||
`./hello`
|
||||
|
||||
- C++
|
||||
```cpp
|
||||
// Your First C++ Program
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::cout << "Hello World!";
|
||||
return 0;
|
||||
}
|
||||
|
||||
```
|
||||
- compiling and running
|
||||
`g++ hello.cpp -o hello` and `./hello` to run
|
||||
Additionally to link packages
|
||||
`g++ main.cpp -Ifltk-1.3.9 -Lfltk-1.3.9/lib -lfltk -lX11 -lXfixes -lXext -lXft -lXrender -lfontconfig -lXcursor -lXinerama -ldl -o main`
|
||||
|
||||
- Java
|
||||
Requirements : openjdk installed
|
||||
Build systems : maven/gradle(optional) for extra packages
|
||||
Config files : pom.xml for maven and build.gradle for gradle
|
||||
```java
|
||||
// Your First Program
|
||||
|
||||
class HelloWorld {
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello, World!");
|
||||
}
|
||||
}
|
||||
```
|
||||
Compiling and running it
|
||||
`javac hello` this will create a bytecode named `HelloWorld.class`
|
||||
to execute the bytecode `java HelloWorld`
|
||||
Theory
|
||||
bytecode is the low level, platform independent code and when we use java command for bytecode it executes in JVM(Java Virtual Machine). This JVM converts bytecode into machine language and then executes it
|
||||
|
||||
Compiling and running with maven
|
||||
`mvn package` to build it
|
||||
`mvn spring-boot:run` to run the sprint boot app
|
||||
|
||||
- Javascript
|
||||
Requirements : node installed
|
||||
Build systems : npm/yarn for managing packages
|
||||
Config files : package.json
|
||||
```js
|
||||
console.log('Hello World!')
|
||||
```
|
||||
Running
|
||||
`node hello.js`
|
||||
for packages
|
||||
`npm i`
|
||||
`npm start`
|
||||
|
||||
- python
|
||||
Requirements : python 3.x installed
|
||||
Build system : pip for managing packages
|
||||
Config file : requirements.txt
|
||||
```py
|
||||
print("Hello World!")
|
||||
```
|
||||
Running
|
||||
`python hello.py`
|
||||
for packages
|
||||
`pip install requiremnts.txt`
|
||||
`python main.py`
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
compression
|
||||
|
||||
- zfs on fly compression
|
||||
65
joplin notion extension/Web Development/Extras/extras.md
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
extras
|
||||
|
||||
- https://github.com/dcloudio/uni-app/blob/dev/README_en-US.md
|
||||
cross platform framework for ios and android with vue.js
|
||||
- https://picsum.photos/images
|
||||
lorem ipsum for photos
|
||||
eg:
|
||||
https://picsum.photos/id/34/367/267
|
||||
https://picsum.photos/id/36/367/267
|
||||
- hacking electron apps
|
||||
https://medium.com/@libaration/decompiling-and-repacking-electron-apps-b9bfbc8390d5
|
||||
https://www.youtube.com/watch?v=jkJWA_CWrQs : Hacking Electron Applications
|
||||
- https://github.com/AxaFrance/oidc-client : oauth 2.0 client for react
|
||||
- neutralinojs : use native webview and uses system libraries and have no dependecies
|
||||
https://github.com/neutralinojs/neutralinojs
|
||||
[neutralinojs-main.zip](../../../_resources/neutralinojs-main.zip)
|
||||
|
||||
|
||||
```bash
|
||||
# Creating a new app
|
||||
npm i -g @neutralinojs/neu
|
||||
neu create hello-world
|
||||
cd hello-world
|
||||
neu run
|
||||
|
||||
# Building your app (No compilation - takes less than a second)
|
||||
neu build
|
||||
```
|
||||
- mise: version manager for multiple languages
|
||||
https://mise.jdx.dev/
|
||||
|
||||
- talking privately in publi channel
|
||||
```txt
|
||||
ok the general process is as follows
|
||||
step 1 is each person makes a pgp keypair
|
||||
it'll just be an rsa or ed25519 keypair or whatever
|
||||
you can get a software like kleopatra or use gpg on linux
|
||||
after you make your keypair, each person shares their public key with everyone else
|
||||
then if person A wants to send a message to person B, person A will use B's public key to encrypt the message
|
||||
|
||||
then since only B has the secret key, only B can read the message
|
||||
```
|
||||
- decentraloized database
|
||||
https://gun.eco/ : database for freedom fighters
|
||||
also gun does not gurantee data persistance. THIS IS BY DESIGN. if no one in the peer graph has that piece of data, the data is gone
|
||||
solution is to have a periodic backup somewhere else. this is what 'relay servers' handle. if you need a piece of data permanently, you keep it at the relay server
|
||||
the server manages its own disk so you as the developer can choose whether to delete a piece of data or not
|
||||
if i delete this data from relay this doesnt effect other p2p right as it is decentralized, i mean it will be gone if it is not there from peer but as long as peers too have it it will be there, answer is yes
|
||||

|
||||
- pgp alternative : https://github.com/FiloSottile/age
|
||||
|
||||
firefox css for making list of extensions in grid interface
|
||||
```css
|
||||
.extension-enabled-section{
|
||||
display: flex;
|
||||
grid-template-rows: revert;
|
||||
flex-wrap: wrap;
|
||||
width: 80vw;
|
||||
}
|
||||
|
||||
.extension-enabled-section addon-card {
|
||||
margin: 1rem;
|
||||
width: 300px;
|
||||
}
|
||||
```
|
||||
137
joplin notion extension/Web Development/Extras/ffmpeg.md
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
ffmpeg
|
||||
|
||||
- For recording a particular section of video
|
||||
https://superuser.com/questions/639402/convert-specific-video-and-audio-track-only-with-ffmpeg
|
||||
`ffmpeg -i input.video -ss hh:mm:ss.ms -t ss output.video`
|
||||
Eg :
|
||||
`ffmpeg -i inputVideo.mkv -ss 00:34:12.00 -t 20 outputVideo.mkv`
|
||||
This will start recording from 34th min 12th sec to 34th min 32sec as 20 after -t is 20s
|
||||
- Choosing codecs, audio tracks
|
||||
`ffmpeg -i Mr.Robot.S01E03.720p.Hindi.English.moviesFlixPro.in.mkv -ss 00:35:18.00 -t 50 -c:v libx264 -c:a ac3 -crf 20 -map 0:0 -map 0:1 recorded1.mp4`
|
||||
|
||||
-c:v : video codec libx264 means popular H.264
|
||||
-c:a audio codec ac3 is audio codec
|
||||
-crf : constant rate factor
|
||||
map is for stream id so 0 represents 1st, 1 represents 2nd and so on. but this can be overwelming and confusing t know which one is audio stream or video stream or subtitles or something else
|
||||
|
||||
`ffmpeg -i inputVideo.mkv -ss 00:35:18.00 -t 50 -c:v libx264 -c:a ac3 -crf 20 -map 0:v:0 -map 0:a:1 recorded1.mp4
|
||||
`
|
||||
`-map 0:v:0` means 1st video track
|
||||
`-map 0:a:1` means 2nd audio track so if there r 2 audio track 2nd audio track will be encoded
|
||||
ac3 audio track may not work in browser so choose `aac` as audio track
|
||||
or
|
||||
`ffmpeg -i "Texas Police Chief arrests woman over facebook post warning neighbors about dirty tap water.mp4" -ss 00:07:00.00 -t 20 -c:v libx264 -crf 20 -map 0:v:0 -map 0:a:0 life_is_political.mp4`
|
||||
|
||||
- extracting video including subtitle
|
||||
- first extract subtitle file
|
||||
`ffmpeg -i input.mkv -map 0:s:0 -c:s srt subtitles.srt`
|
||||
or
|
||||
`ffmpeg -i input.mkv subtitles.srt`
|
||||
|
||||
- then use some script or use online tool like https://subshifter.bitsnbites.eu/ to offset subtitles respective to time range of video extracted
|
||||
```py
|
||||
import re
|
||||
|
||||
def adjust_timing(srt_file, haste_seconds):
|
||||
with open(srt_file, 'r') as file:
|
||||
content = file.readlines()
|
||||
|
||||
adjusted_content = []
|
||||
for line in content:
|
||||
# Match timestamps
|
||||
if re.match(r'\d\d:\d\d:\d\d,\d{3} --> \d\d:\d\d:\d\d,\d{3}', line):
|
||||
start, end = line.split(' --> ')
|
||||
# Adjust both start and end times
|
||||
new_start = adjust_time(start, haste_seconds)
|
||||
new_end = adjust_time(end.strip(), haste_seconds)
|
||||
adjusted_content.append(f"{new_start} --> {new_end}\n")
|
||||
else:
|
||||
adjusted_content.append(line)
|
||||
|
||||
with open('adjusted_subtitles.srt', 'w') as file:
|
||||
file.writelines(adjusted_content)
|
||||
|
||||
def adjust_time(timestamp, haste_seconds):
|
||||
hours, minutes, seconds = map(float, re.split('[:,]', timestamp))
|
||||
total_seconds = hours * 3600 + minutes * 60 + seconds - haste_seconds
|
||||
if total_seconds < 0:
|
||||
total_seconds = 0 # Prevent negative timestamps
|
||||
new_hours = int(total_seconds // 3600)
|
||||
new_minutes = int((total_seconds % 3600) // 60)
|
||||
new_seconds = total_seconds % 60
|
||||
return f"{int(new_hours):02}:{int(new_minutes):02}:{new_seconds:06.3f}".replace('.', ',')
|
||||
|
||||
adjust_timing('subtitles.srt', 300) # Hasten by 5 minutes (300 seconds)
|
||||
|
||||
```
|
||||
- then extract video without subtitle like before then merge subtitle
|
||||
`ffmpeg -i input.mkv -ss 00:35:18.00 -t 50 -crf 20 -map 0:v:0 -map 0:a:0 recorded1.mp4`
|
||||
and
|
||||
`ffmpeg -i recorded1.mp4 -i subtitles-resync.srt -c copy -c:s mov_text outfile.mp4`
|
||||
and here this outfile.mp4 is desired file with extract video,audio and subtitles
|
||||
|
||||
- convert video to audio
|
||||
`ffmpeg -i video.mp4 -b:a 192K -vn music.mp3` or `ffmpeg -i video.mp4 -vn music.mp3`
|
||||
here `-vn` means no video
|
||||
`-b:a 192K` : to target audio stream to tell it for 192k bitrate
|
||||
|
||||
for converting all videos in folder to audio
|
||||
```bash
|
||||
for arg in * ; do
|
||||
ffmpeg -i "${arg}" -vn "${arg%%.*}.mp3"
|
||||
done
|
||||
```
|
||||
|
||||
|
||||
** get information about multimedia file**
|
||||
`ffprobe -i input.mp4`
|
||||
|
||||
|
||||
merging all videos
|
||||
https://www.mux.com/articles/stitch-multiple-videos-together-with-ffmpeg
|
||||
- create `inputs.txt` file and add the videos to be merged
|
||||
```txt
|
||||
file 'video1.mp4'
|
||||
file 'video2.mp4'
|
||||
file 'video3.mp4'
|
||||
|
||||
```
|
||||
- then simply run this `ffmpeg -f concat -safe 0 -i inputs.txt -c copy output.mp4`
|
||||
`-f concat`: Specifies the concatenation format.
|
||||
`-safe 0`: Prevents file path errors if your filenames use relative or absolute paths.
|
||||
`-c copy`: Copies the video and audio streams directly without re-encoding, preserving 100% quality.
|
||||
|
||||
**Method 2: Different Formats (Requires Re-encoding)**
|
||||
If your clips have different resolutions, frame rates, or codecs, you must use a Complex Filtergraph. This re-encodes the segments so they blend smoothly into a single unified format. [2, 8]
|
||||
Run this single command to merge two mismatched files: [9, 10, 11]
|
||||
|
||||
`ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v][0:a][1:v][1:a] concat=n=2:v=1:a=1 [v][a]" -map "[v]" -map "[a]" output.mp4`
|
||||
|
||||
or
|
||||
|
||||
`ffmpeg -i video_480p.mp4 -i video_720p.mp4 -filter_complex \
|
||||
"[0:v]scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2[v0]; \
|
||||
[v0][0:a][1:v][1:a]concat=n=2:v=1:a=1[v][a]" \
|
||||
-map "[v]" -map "[a]" -c:v libx264 -crf 23 -c:a aac final_output.mp4`
|
||||
|
||||
|
||||
* -i video1.mp4 -i video2.mp4: Specifies the input files sequentially.
|
||||
* [0:v][0:a][1:v][1:a]: Tells FFmpeg to extract the video and audio streams from input 0 (first file) and input 1 (second file).
|
||||
* concat=n=2:v=1:a=1: Combines the 2 input segments (n=2) into 1 output video stream (v=1) and 1 output audio stream (a=1).
|
||||
* -map "[v]" -map "[a]": Maps the newly joined streams to the final output file. [8, 9, 12]
|
||||
|
||||
|
||||
or if only 1 file is being different then only convert that one like others
|
||||
480 one converted to like of 720p one here
|
||||
`ffmpeg -i video_480p.mp4 -i video_720p.mp4 -filter_complex \
|
||||
"[0:v]scale=1280:720:force_original_aspect_ratio=decrease,pad=1280:720:(ow-iw)/2:(oh-ih)/2[v]" \
|
||||
-map "[v]" -map 0:a -c:v libx264 -c:a aac converted_480p.mp4`
|
||||
|
||||
then later merge them with others. though this will work if they were using those libx264 and aac audio. to be more safer some manual work like finding audio and video encoding via ffprobe. so for the witcher 3 recorded videos it was
|
||||
|
||||
` Video: h264 (Main) (avc1 / 0x31637661), yuv420p(progressive), 1920x1080 [SAR 1:1 DAR 16:9], 10006 kb/s, 28.91 fps, 60 tbr, 30k tbn (default)`
|
||||
|
||||
and to convert 480p ones to witcher one
|
||||
`ffmpeg -i video_480p.mp4 -vf "scale=1920:1080:force_original_aspect_ratio=decrease,pad=1920:1080:(ow-iw)/2:(oh-ih)/2" -r 28.91 -c:v libx264 -profile:v main -c:a copy converted_480p.mp4`
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
11ty
|
||||
https://snipcart.com/blog/11ty-tutorial
|
||||
|
||||
- install globally using `npm install -g @11ty/eleventy`
|
||||
- to build it use `eleventy` and for hot reloading in dev mode use `eleventy --serve`.
|
||||
|
||||
|
||||
for integrating with react
|
||||
https://github.com/kaicataldo/eleventy-plugin-react
|
||||
sample project : [react.zip](../../../../_resources/react.zip)
|
||||
|
||||
|
||||
|
||||
- install all thise required modules
|
||||
`npm install eleventy-plugin-react babel-loader @babel/core @babel/preset-env @babel/preset-react react react-dom core-js@3 regenerator-runtime`
|
||||
- in project , in .eleventy.js configuration is like this: the layout with .njk and postprocess option is changed to just return html because rest part is hamdled by this layout `base.njk`.
|
||||
- for custom layout for separate pages do this in `.eleventy.js`
|
||||
```js
|
||||
module.exports = function(eleventyConfig) {
|
||||
eleventyConfig.addPlugin(eleventyReact);
|
||||
|
||||
// Set custom layouts for different pages
|
||||
eleventyConfig.addPassthroughCopy("src/assets"); // Optional: For copying static assets
|
||||
|
||||
// This is where you can set different layouts based on conditions
|
||||
eleventyConfig.addGlobalData("layout", (data) => {
|
||||
if (data.page.url === "/about/") {
|
||||
return "about-layout.njk"; // Use 'about-layout.njk' for the about page
|
||||
} else {
|
||||
return "base.njk"; // Default layout for all other pages
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
dir: {
|
||||
input: "src/pages", // Input directory for pages
|
||||
output: "_site", // Output directory for generated static files
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
- in gatsby for client side component
|
||||
```js
|
||||
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
const ClientOnlyComponent = () => {
|
||||
const [isClient, setIsClient] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setIsClient(true); // This sets isClient to true only on the client-side
|
||||
}, []); // The empty dependency array ensures this effect runs only once after the initial render
|
||||
|
||||
if (!isClient) {
|
||||
return null; // Avoid rendering anything on the server-side
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
This component is rendered on the client-side only.
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ClientOnlyComponent;
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
Blogging
|
||||
|
||||
- Blog page will contain list of posts and these posts are in `_posts`. for instance one post can be
|
||||
`2018-08-20-bananas.md`
|
||||
```md
|
||||
---
|
||||
layout: post
|
||||
author: jill
|
||||
---
|
||||
|
||||
A banana is an edible fruit – botanically a berry – produced by several
|
||||
kinds of large herbaceous flowering plants in the genus Musa.
|
||||
|
||||
In some countries, bananas used for cooking may be called "plantains",
|
||||
distinguishing them from dessert bananas. The fruit is variable in size,
|
||||
color, and firmness, but is usually elongated and curved, with soft
|
||||
flesh rich in starch covered with a rind, which may be green, yellow,
|
||||
red, purple, or brown when ripe.
|
||||
```
|
||||
- Creating layout for the post. at `_layouts/post.html`
|
||||
```html
|
||||
---
|
||||
layout: default
|
||||
---
|
||||
<h1>{{ page.title }}</h1>
|
||||
<p>{{ page.date | date_to_string }} - {{ page.author }}</p>
|
||||
|
||||
{{ content }}
|
||||
```
|
||||
`date_to_string` filter, this formats a date into a nicer format
|
||||
- listing posts : posts will be available at `site.posts`. at `/blog.html`
|
||||
```html
|
||||
---
|
||||
layout: default
|
||||
title: Blog
|
||||
---
|
||||
|
||||
<h1> Latest Posts </h1>
|
||||
|
||||
<ul>
|
||||
{% for post in site.posts %}
|
||||
<li>
|
||||
<h2> <a href="{{post.url}}"> {{post.title}} </a> </h2>
|
||||
{{post.excerpt}}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
```
|
||||
There’s a few things to note with this code:
|
||||
- `post.url` is automatically set by Jekyll to the output path of the post
|
||||
- `post.title` is pulled from the post filename and can be overridden by setting title in front matter
|
||||
- `post.excerpt` is the first paragraph of content by default. excerpt literally means short piece taken from something.
|
||||
- adding blog entry in `_data/navigation.yml`
|
||||
```yml
|
||||
- name: Home
|
||||
link: /
|
||||
- name: About
|
||||
link: /about.html
|
||||
- name: Blog
|
||||
link: /blog.html
|
||||
```
|
||||
- more posts
|
||||
at `_posts/2018-08-21-apples.md`
|
||||
```md
|
||||
---
|
||||
layout: post
|
||||
author: jill
|
||||
---
|
||||
An apple is a sweet, edible fruit produced by an apple tree.
|
||||
|
||||
Apple trees are cultivated worldwide, and are the most widely grown
|
||||
species in the genus Malus. The tree originated in Central Asia, where
|
||||
its wild ancestor, Malus sieversii, is still found today. Apples have
|
||||
been grown for thousands of years in Asia and Europe, and were brought
|
||||
to North America by European colonists.
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
Data files
|
||||
- It is important to separate the content from layouts so store them in `_data` folder. Data files supported are YAML, JSON, and CSV. YAML ones are most common for this
|
||||
- To create a array of objects where each objects have property ie `name` and `link`
|
||||
at `_data/navigation.yml`
|
||||
```yml
|
||||
- name: Home
|
||||
link: /
|
||||
- name: About
|
||||
link: /about.html
|
||||
```
|
||||
- this data will be available at `site.data.navigation`. In ` _includes/navigation.html`
|
||||
```html
|
||||
<nav>
|
||||
{% for item in site.data.navigation %}
|
||||
<a href="{{ item.link }}" {% if page.url == item.link %} style="color: red;"{% endif %}>
|
||||
{{ item.name }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</nav>
|
||||
```
|
||||
|
||||
|
||||
**Assets**
|
||||
- Other files like css,js and images can be included in `assets` folder
|
||||
```
|
||||
.
|
||||
├── assets
|
||||
│ ├── css
|
||||
│ ├── images
|
||||
│ └── js
|
||||
...
|
||||
```
|
||||
- css is necessary too as inline styles are not a good idea always so in `assets/css/styles.scss`
|
||||
```css
|
||||
---
|
||||
---
|
||||
@import "main";
|
||||
```
|
||||
- then create `_sass` at root directory as `@import main` will tell to look for file `main.scss` at `_sass`
|
||||
so at `_sass/main.scss`
|
||||
```scss
|
||||
.current {
|
||||
color: green;
|
||||
}
|
||||
```
|
||||
in `_layouts/default.html` add this styles.css under `<head>`
|
||||
```html
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>{{ page.title }}</title>
|
||||
<link rel="stylesheet" href="/assets/css/styles.css">
|
||||
</head>
|
||||
<body>
|
||||
{% include navigation.html %}
|
||||
{{ content }}
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
- finally add the class `current` too in `_includes/navigation.html`
|
||||
```html
|
||||
<nav>
|
||||
{% for item in site.data.navigation %}
|
||||
<a href="{{ item.link }}"{% if page.url == item.link %} class="current"{% endif %}>{{ item.name }}</a>
|
||||
{% endfor %}
|
||||
</nav>
|
||||
```
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
Deployment
|
||||
- Before deployment there is something called collections which can be defined in `_config.yml` in root of site so there is site.data, site.posts which are predefined so for more like site.authors type following in `_config.yml`
|
||||
```yml
|
||||
collections:
|
||||
authors:
|
||||
output: true
|
||||
```
|
||||
By default it wont output to page so using this when clicked on author it will redirect to its page
|
||||
More refer to https://jekyllrb.com/docs/step-by-step/09-collections/
|
||||
- Now going back to root of project so type `cd ..`. as jekyll is installed and all the versions are locked so in order to serve or build with those versions instead of system ones use `bundle exec jekyll serve` instead of `jekyll serve`. this will restrict the enviroment to use gems set in Gemfile.
|
||||
- Some other important plugins
|
||||
- jekyll-sitemap - Creates a sitemap file to help search engines index content
|
||||
- jekyll-feed - Creates an RSS feed for your posts
|
||||
- jekyll-seo-tag - Adds meta tags to help with SEO
|
||||
- in Gemfile
|
||||
```
|
||||
source 'https://rubygems.org'
|
||||
|
||||
gem "jekyll"
|
||||
|
||||
group :jekyll_plugins do
|
||||
gem "jekyll-sitemap"
|
||||
gem "jekyll-feed"
|
||||
gem "jekyll-seo-tag"
|
||||
end
|
||||
```
|
||||
- in `_config.yml`
|
||||
```yml
|
||||
plugins:
|
||||
- jekyll-feed
|
||||
- jekyll-sitemap
|
||||
- jekyll-seo-tag
|
||||
```
|
||||
now install by `bundle update`
|
||||
in `_layouts/default.html`
|
||||
add these tags
|
||||
```html
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>{{ page.title }}</title>
|
||||
<link rel="stylesheet" href="/assets/css/styles.css">
|
||||
{% feed_meta %}
|
||||
{% seo %}
|
||||
</head>
|
||||
<body>
|
||||
{% include navigation.html %}
|
||||
{{ content }}
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
Extras
|
||||
|
||||
- Sources
|
||||
https://jekyllthemes.io/free
|
||||
https://themefisher.com/jekyll-blog-themes
|
||||
- Custom themes
|
||||
https://jekyllthemes.io/theme/minimal-mistakes
|
||||
https://themefisher.com/products/parsa-jekyll
|
||||
https://github.com/bitbrain/jekyll-dash : make sure to fix related_posts by adding this https://github.com/toshimaru/jekyll-tagging-related_posts
|
||||
|
||||
- when downloading templates/themes it maybe necessary to use bundle of different version. So to install of different version say `2.2.34`, install with `gem install bundler:2.2.34` and rerun bundler using `bundle _2.2.34_`.
|
||||
- jekyll dash info
|
||||
in one of custom theme of bitbrain in order to remove the check based list, go to `_sass > dash > _layouts.scss` and finr `ul > li` and change there
|
||||
- gh-pages : when uploading make sure to add a baseurl in `_config.yml` like this
|
||||
```yml
|
||||
baseurl: /reponame
|
||||
```
|
||||
also when linking media assets make sure to include baseurl by `{{site.baseurl}}` like this.
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
Layouts
|
||||
A way to creating template of page and also supporting markdown
|
||||
|
||||
- In root directory (`site` here) create `_layouts` and create `default.html`
|
||||
In `_layouts/default.html`
|
||||
```html
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>{{ page.title }}</title>
|
||||
</head>
|
||||
<body>
|
||||
{{ content }}
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
- html
|
||||
```html
|
||||
---
|
||||
layout: default
|
||||
title: Home
|
||||
---
|
||||
<h1>{{ "Hello World!" | downcase }}</h1>
|
||||
```
|
||||
- create a about.md file in root directory of site and add following
|
||||
```md
|
||||
---
|
||||
layout: default
|
||||
title: About
|
||||
---
|
||||
# About page
|
||||
|
||||
This page tells you a little bit about me.
|
||||
```
|
||||
Now opening `http://localhost:4000/about.html` will open this about.md with markdown content rendered
|
||||
|
||||
|
||||
Includes
|
||||
- The `include` tag allows you to include content from another file stored in an `_includes` folder.
|
||||
at `_includes/navigation.html`. here `page.url` is used to detect url so that current page link will be colored as red
|
||||
```html
|
||||
<nav>
|
||||
<a href="/" {% if page.url=='/' %} style="color: red;"{% endif %} >Home</a>
|
||||
<a href="/about.html" {% if page.url=='/about.html' %} style="color: red;"{% endif %} >About</a>
|
||||
</nav>
|
||||
```
|
||||
Now using this in `_layouts/default.html`
|
||||
```html
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>{{ page.title }}</title>
|
||||
</head>
|
||||
<body>
|
||||
{% include navigation.html %}
|
||||
{{ content }}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
jekyll installation
|
||||
https://jekyllrb.com/docs/step-by-step/01-setup/
|
||||
|
||||
1. After ruby is installed,install jekyll and bundler using gem command
|
||||
`gem install jekyll bundler`
|
||||
2. Set the environment path of bundler and other plugins in environment path. Path to be added is
|
||||
`/home/hpes/.local/share/gem/ruby/3.3.0/bin`
|
||||
3. Edit the Gemfile in a text editor and add jekyll as a dependency:
|
||||
`gem "jekyll"`
|
||||
4. Now change the config path of bundle as it will use system environment ruby which wont be accessibe
|
||||
`bundle config path <path>` here `<path>` can be `/Documents/ruby` or any path owned by current user
|
||||
5. run `bundle` : to install gem modules
|
||||
|
||||
|
||||
demo
|
||||
1. Create a folder say `site` and cd into it
|
||||
2. run `jekyll serve` to go to dev mode (to see live changes) and `jekyll build` to create optimised build
|
||||
also use this to refresh the browser too
|
||||
`jekyll serve --livereload` and other flags for different host and port are `--host` and `--port`
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
liquid
|
||||
|
||||
A templating language have 3 components ie objects, tags and filter
|
||||
1. objects are for values of variables. `{{page.title}}` will display value of `page.title`
|
||||
2. tags : for control flow
|
||||
```html
|
||||
{% if page.show_sidebar %}
|
||||
<div class="sidebar">
|
||||
sidebar content
|
||||
</div>
|
||||
{% endif %}
|
||||
```
|
||||
3. fllter : to change output
|
||||
eg: `{{ "hi" | capitalize }}` will display `Hi`
|
||||
|
||||
|
||||
**Front matter**
|
||||
Front matter is a snippet of YAML placed between two triple-dashed lines at the start of a file.
|
||||
- front matter variables
|
||||
```
|
||||
---
|
||||
my_number: 5
|
||||
---
|
||||
```
|
||||
calling value front end matter variable
|
||||
```
|
||||
{{ page.my_number }}
|
||||
```
|
||||
example
|
||||
```html
|
||||
---
|
||||
# front matter tells Jekyll to process Liquid
|
||||
title: home
|
||||
---
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>{{ page.title | capitalize }}</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>{{ "Hello World!" | downcase }}</h1>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
364
joplin notion extension/Web Development/Extras/nginx.md
Normal file
|
|
@ -0,0 +1,364 @@
|
|||
nginx
|
||||
[nginx.md](../../../_resources/nginx.md)
|
||||
|
||||
- to start nginx server with python use
|
||||
`$ python3 -m http.server 8085`
|
||||
for a specific directory use
|
||||
`python3 -m http.server -d /path/to/your/directory [PORT_NUMBER]`
|
||||
|
||||
## Tip
|
||||
- Instead of buying or getting actual domain, go to `/etc/hosts` and add the line `127.0.0.1 <domain_name>`. so when u type this added domain name in browser it will redirect to the ip address automatically
|
||||
Eg:
|
||||
```yaml
|
||||
server {
|
||||
listen 80;
|
||||
|
||||
server_name skdnbdasbn.org;
|
||||
|
||||
|
||||
location / {
|
||||
|
||||
root /var/www/testFlex;
|
||||
|
||||
index index.html index.htm;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name klsjdisabj.org;
|
||||
|
||||
location / {
|
||||
|
||||
root /var/www/test2;
|
||||
|
||||
index index.html index.htm;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
To host your `index.html` file using Nginx on Arch Linux, you'll need to go through a few straightforward steps: installation, configuration, and testing. Here's a beginner-friendly guide to get you started:
|
||||
|
||||
### 1. Installing Nginx
|
||||
|
||||
First, you need to install Nginx. Arch Linux uses pacman as its package manager, so you can easily install Nginx from the terminal. Open your terminal and run the following command:
|
||||
|
||||
```bash
|
||||
sudo pacman -Sy nginx
|
||||
```
|
||||
|
||||
This command will update your package database and install Nginx.
|
||||
|
||||
### 2. Starting and Enabling Nginx Service
|
||||
|
||||
After installing, you need to start and enable the Nginx service to ensure it runs on boot. Use systemctl to manage the Nginx service:
|
||||
|
||||
```bash
|
||||
sudo systemctl start nginx
|
||||
sudo systemctl enable nginx
|
||||
```
|
||||
|
||||
### 3. Configuring Nginx
|
||||
|
||||
Once Nginx is installed, you'll need to configure it to serve your `index.html`. Nginx configurations are stored in `/etc/nginx/`. The primary configuration file is `/etc/nginx/nginx.conf`, but for site-specific configurations, we'll use the `/etc/nginx/sites-available/` and `/etc/nginx/sites-enabled/` directories, which you might need to create. Arch Linux's default setup usually doesn't include these, and instead, you can place your configuration in `/etc/nginx/nginx.conf` or create a specific `server` block file within `/etc/nginx/conf.d/`.
|
||||
|
||||
For a cleaner setup, let’s create `sites-available` and `sites-enabled` directories and include them in our Nginx configuration:
|
||||
|
||||
```bash
|
||||
sudo mkdir /etc/nginx/sites-available
|
||||
sudo mkdir /etc/nginx/sites-enabled
|
||||
```
|
||||
|
||||
Then, open `/etc/nginx/nginx.conf` with your preferred text editor (like nano or vim):
|
||||
|
||||
```bash
|
||||
sudo nano /etc/nginx/nginx.conf
|
||||
```
|
||||
|
||||
Find the `http` block and add the following line at the bottom of it to include any configurations you'll put in `sites-enabled`:
|
||||
|
||||
```nginx
|
||||
include /etc/nginx/sites-enabled/*;
|
||||
```
|
||||
|
||||
Now, create a configuration file for your site in the `sites-available` directory. You can name it after your domain or project
|
||||
|
||||
4. **Create a new configuration file** for your site in the `sites-available` directory. Replace `yourdomain.com` with your domain name or `localhost` if you don’t have one:
|
||||
```
|
||||
sudo nano sites-available/yourdomain.com
|
||||
```
|
||||
|
||||
5. Add the following server block (adjust the `server_name` if using a domain, and change `/path/to/your/index.html` to the actual path of your `index.html` file):
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name yourdomain.com; # Or localhost
|
||||
location / {
|
||||
root /path/to/your;
|
||||
index index.html;
|
||||
}
|
||||
}
|
||||
```
|
||||
Save and close the file.
|
||||
|
||||
6. **Create a symbolic link** to enable the site:
|
||||
```
|
||||
sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/
|
||||
```
|
||||
|
||||
and finally start and enable nginx service
|
||||
|
||||
- multiple sites in different domain
|
||||
|
||||
`sites/available/first`
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name yourdomain1.com;
|
||||
location / {
|
||||
root /path/to/first;
|
||||
index index.html;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
```
|
||||
`sites/available/first`
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name yourdomain2.com;
|
||||
location / {
|
||||
root /path/to/second;
|
||||
index index.html;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- For multiple subdomains for one domain and hosting different sites
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name circux.net;
|
||||
|
||||
# Main configuration for the circux.net domain
|
||||
# You can put your main site configuration here
|
||||
# ...
|
||||
|
||||
# Additional server blocks for subdomains
|
||||
server {
|
||||
listen 80;
|
||||
server_name play.circux.net;
|
||||
|
||||
# Configuration for the play.circux.net subdomain
|
||||
# You can put specific settings for this subdomain here
|
||||
# ...
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
server_name animal.circux.net;
|
||||
|
||||
# Configuration for the animal.circux.net subdomain
|
||||
# You can put specific settings for this subdomain here
|
||||
# ...
|
||||
}
|
||||
|
||||
# Add more server blocks for additional subdomains as needed
|
||||
# ...
|
||||
}
|
||||
```
|
||||
|
||||
- others
|
||||
Test Nginx Configuration:
|
||||
|
||||
Check if there are any syntax errors in your Nginx configuration:
|
||||
|
||||
`sudo nginx -t`
|
||||
|
||||
Reload Nginx:
|
||||
|
||||
Once the configuration test passes, reload Nginx to apply the changes:
|
||||
|
||||
`sudo systemctl reload nginx`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### Nodejs server
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name yourdomain.com;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:3000; # Change the port if your Node.js app listens on a different port
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
|
||||
# Additional configuration can be added here
|
||||
# such as SSL/TLS settings, caching, etc.
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
### from llm
|
||||
|
||||
Great! You're almost there. Now that you have a subdomain set up in **FreeDNS (Afraid.org)**, and a **Node.js app running on a specific TCP port on your DigitalOcean VPS**, here’s how to link it all together so that your subdomain points to your Node.js app.
|
||||
|
||||
---
|
||||
|
||||
### 🔧 Step-by-Step Guide
|
||||
|
||||
---
|
||||
|
||||
#### ✅ 1. **Ensure Your Node.js App is Running**
|
||||
|
||||
Let’s say your Node.js app is running on:
|
||||
|
||||
* **IP:** `your_vps_ip`
|
||||
* **Port:** `3000`
|
||||
|
||||
You can test it by visiting `http://your_vps_ip:3000` in a browser.
|
||||
|
||||
---
|
||||
|
||||
#### ✅ 2. **Point Subdomain to Your VPS in FreeDNS**
|
||||
|
||||
In **FreeDNS (Afraid.org)**:
|
||||
|
||||
* Go to your **subdomain settings**.
|
||||
* Set the **A record** of your subdomain (e.g. `app.yourdomain.com`) to the **public IP** of your DigitalOcean VPS.
|
||||
|
||||
✔️ **Example:**
|
||||
|
||||
```
|
||||
Type: A
|
||||
Subdomain: app.yourdomain.com
|
||||
Destination: your_vps_ip
|
||||
```
|
||||
|
||||
DNS changes can take up to a few minutes (sometimes longer) to propagate.
|
||||
|
||||
---
|
||||
|
||||
#### ✅ 3. **Use a Reverse Proxy with NGINX (Recommended)**
|
||||
|
||||
Since you’re serving from a port like `3000`, you don't want users to access it via `http://yourdomain.com:3000`. Instead, use **NGINX** to expose it on port 80 (HTTP) or 443 (HTTPS).
|
||||
|
||||
---
|
||||
|
||||
#### 🔄 Install and Configure NGINX
|
||||
|
||||
**Step 1: Install NGINX**
|
||||
|
||||
```bash
|
||||
sudo apt update
|
||||
sudo apt install nginx
|
||||
```
|
||||
|
||||
**Step 2: Create a New NGINX Config File**
|
||||
|
||||
```bash
|
||||
sudo nano /etc/nginx/sites-available/app
|
||||
```
|
||||
|
||||
**Example Configuration:**
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 80;
|
||||
server_name app.yourdomain.com;
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:3000;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Step 3: Enable the Site**
|
||||
|
||||
```bash
|
||||
sudo ln -s /etc/nginx/sites-available/app /etc/nginx/sites-enabled/
|
||||
sudo nginx -t # test config
|
||||
sudo systemctl restart nginx
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### ✅ 4. **(Optional) Add HTTPS with Let’s Encrypt**
|
||||
|
||||
You can secure your site with HTTPS using **Certbot**:
|
||||
|
||||
```bash
|
||||
sudo apt install certbot python3-certbot-nginx
|
||||
sudo certbot --nginx -d app.yourdomain.com
|
||||
```
|
||||
|
||||
This will automatically update your NGINX config to use SSL.
|
||||
|
||||
to renew certificate
|
||||
`sudo certbot renew`
|
||||
|
||||
---
|
||||
|
||||
### 🎉 Done!
|
||||
|
||||
Now, visiting `http://app.yourdomain.com` (or `https://app.yourdomain.com` if you added SSL) will open your Node.js app running on port `3000`.
|
||||
|
||||
---
|
||||
|
||||
If you want me to walk you through any part (e.g. setting up NGINX or Certbot), just tell me where you're at and I’ll guide you!
|
||||
|
||||
|
||||
|
||||
summary of hosting a site
|
||||
|
||||
1. run that site/service locally with some port
|
||||
2. in nginx just to 80 and map your internal port and also provide domain most porobably a domain with dns record ie subdomain or cname(alias of subdomain). so domain is `example.com` so subdomain is `sbdomain.example.com`. domain is not bound to ip but subdomain is which is also `A` dns record
|
||||
3. to add dns record use services like cloudfare provides name server.add dns record and map to ip address and link name server provided by clidfare to domain registry site.
|
||||
4. finally its recommened to add ssl certificate to get https which ensures trust
|
||||
|
||||
|
||||
|
||||
### Extras
|
||||
1. There is limit to file upload set by nginx and it can be changed by
|
||||
```sh
|
||||
nano /etc/nginx/nginx.conf
|
||||
# Add a line in the http, server or location section:
|
||||
client_max_body_size 100M;
|
||||
|
||||
# test syntax
|
||||
sudo nginx -t
|
||||
|
||||
# reload nginx
|
||||
sudo nginx -s reload
|
||||
```
|
||||
reference : https://stackoverflow.com/questions/24306335/413-request-entity-too-large-file-upload-issue
|
||||
|
|
@ -0,0 +1,508 @@
|
|||
rclone and rsync
|
||||
|
||||
- rclone browser
|
||||
https://github.com/kapitainsky/RcloneBrowser
|
||||
https://rclone.org/gui/
|
||||
`rclone rcd --rc-web-gui`
|
||||
- sync to remote storage
|
||||
https://research.it.iastate.edu/guides/pronto/file_transfers/rclone/
|
||||
https://rclone.org/internetarchive/
|
||||
|
||||
[Box - Pronto User Documentation.pdf](../../../_resources/Box%20-%20Pronto%20User%20Documentation.pdf)
|
||||
```bash
|
||||
rclone config
|
||||
# Select new remote and when ask for a name, give one
|
||||
# After that it will ask what cloud storage u want be able to sync
|
||||
# Then it will ask you for api cresentials or something else
|
||||
# but choose to rather login with your brower for simplicity to authorize access
|
||||
|
||||
```
|
||||
|
||||
`rclone sync /notes remote_cloud_name:/syncF/`
|
||||
`remote_cloud_name` is the name of remote
|
||||
|
||||
- simply copy
|
||||
`rclone copy source dest`
|
||||
|
||||
- encryption
|
||||
- For configuring select `crypt` when asked for cloud provider then select another config like `remote_box` as `remote_box` is the name of config for box account
|
||||
https://www.maketecheasier.com/use-rclone-crypt-encrypt-files/
|
||||
To encrypt before uploading to host
|
||||
https://small.fileditchstuff.me/s6/FXtvAmOlrKQaaPVabACZ.mp4
|
||||
- completely deleting directory with its contents
|
||||
`rclone purge remote_box:/syncF`
|
||||
- removing files
|
||||
`rclone delete remote:box/syncF/filesList.txt`
|
||||
- list contents of remote directory
|
||||
`rclone lsf remote_name:path/to/directory`
|
||||
- excluding files
|
||||
`rclone copy . ./destination/ --exclude="node_modules/**" --exclude=".*/"`
|
||||
`.*/` represents directories which starts with dot
|
||||
- creating a shatable link
|
||||
`rclone link remote:/path/to/file`
|
||||
|
||||
- mount
|
||||
` rclone mount keepass_drop:/ ~/Dropbox_keepaas --daemon`
|
||||
- unmount
|
||||
`fusermount -u ~/Dropbox_keepaas`
|
||||
|
||||
|
||||
**Internet archive**
|
||||
- When configuring provide access key and secret key. Go to this url https://archive.org/account/s3.php to find
|
||||
- For uploading in internet archive first we need to give a unique identifier which acts like bucket
|
||||
Choose any name like `itemqwerzxc` and use this command
|
||||
`rclone copy Wow\!\ That\'s\ Loud.zip rearchive:itemqwerzxc`
|
||||
- For downloading
|
||||
`rclone copy rearchive:itemqwerzxc downloaded_from_archive/`
|
||||
- encryption wont be easy and might not work. better to use zipped file maybe. Also use different itemId (unique identifier than prev unencrypted one like `rearchive:itemqwerzxcenc`)
|
||||
- to serve directory through http
|
||||
`rclone serve http /path/to/dir --addr :8081`
|
||||
|
||||
|
||||
**Supported cloud providers**
|
||||
```text
|
||||
• 1Fichier
|
||||
|
||||
• Akamai Netstorage
|
||||
|
||||
• Alibaba Cloud (Aliyun) Object Storage System (OSS)
|
||||
|
||||
• Amazon Drive
|
||||
|
||||
• Amazon S3
|
||||
|
||||
• Backblaze B2
|
||||
|
||||
• Box
|
||||
|
||||
• Ceph
|
||||
|
||||
• China Mobile Ecloud Elastic Object Storage (EOS)
|
||||
|
||||
• Arvan Cloud Object Storage (AOS)
|
||||
|
||||
• Citrix ShareFile
|
||||
|
||||
• Cloudflare R2
|
||||
|
||||
• DigitalOcean Spaces
|
||||
|
||||
• Digi Storage
|
||||
|
||||
• Dreamhost
|
||||
|
||||
• Dropbox
|
||||
|
||||
• Enterprise File Fabric
|
||||
|
||||
• Fastmail Files
|
||||
|
||||
• FTP
|
||||
|
||||
• Google Cloud Storage
|
||||
|
||||
• Google Drive
|
||||
|
||||
• Google Photos
|
||||
|
||||
• HDFS
|
||||
|
||||
• Hetzner Storage Box
|
||||
|
||||
• HiDrive
|
||||
|
||||
• HTTP
|
||||
|
||||
• ImageKit
|
||||
|
||||
• Internet Archive
|
||||
|
||||
• Jottacloud
|
||||
|
||||
• IBM COS S3
|
||||
|
||||
• IDrive e2
|
||||
|
||||
• IONOS Cloud
|
||||
|
||||
• Koofr
|
||||
|
||||
• Leviia Object Storage
|
||||
|
||||
• Liara Object Storage
|
||||
|
||||
• Linkbox
|
||||
|
||||
• Linode Object Storage
|
||||
|
||||
• Mail.ru Cloud
|
||||
|
||||
• Memset Memstore
|
||||
|
||||
• Mega
|
||||
|
||||
• Memory
|
||||
|
||||
• Microsoft Azure Blob Storage
|
||||
|
||||
• Microsoft Azure Files Storage
|
||||
|
||||
• Microsoft OneDrive
|
||||
|
||||
• Minio
|
||||
|
||||
• Nextcloud
|
||||
|
||||
• OVH
|
||||
|
||||
• Blomp Cloud Storage
|
||||
|
||||
• OpenDrive
|
||||
|
||||
• OpenStack Swift
|
||||
|
||||
• Oracle Cloud Storage Swift
|
||||
|
||||
• Oracle Object Storage
|
||||
|
||||
• ownCloud
|
||||
|
||||
• pCloud
|
||||
|
||||
• Petabox
|
||||
|
||||
• PikPak
|
||||
|
||||
• premiumize.me
|
||||
|
||||
• put.io
|
||||
|
||||
• Proton Drive
|
||||
|
||||
• QingStor
|
||||
|
||||
• Qiniu Cloud Object Storage (Kodo)
|
||||
|
||||
• Quatrix by Maytech
|
||||
|
||||
• Rackspace Cloud Files
|
||||
|
||||
• rsync.net
|
||||
|
||||
• Scaleway
|
||||
|
||||
• Seafile
|
||||
|
||||
• Seagate Lyve Cloud
|
||||
|
||||
• SeaweedFS
|
||||
|
||||
• SFTP
|
||||
|
||||
• Sia
|
||||
|
||||
• SMB / CIFS
|
||||
|
||||
• StackPath
|
||||
|
||||
• Storj
|
||||
|
||||
• Synology
|
||||
|
||||
• SugarSync
|
||||
|
||||
• Tencent Cloud Object Storage (COS)
|
||||
|
||||
• Uptobox
|
||||
|
||||
• Wasabi
|
||||
|
||||
• WebDAV
|
||||
|
||||
• Yandex Disk
|
||||
|
||||
• Zoho WorkDrive
|
||||
|
||||
• The local filesystem
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Categorized
|
||||
```text
|
||||
1 / 1Fichier
|
||||
\ (fichier)
|
||||
2 / Akamai NetStorage
|
||||
\ (netstorage)
|
||||
3 / Alias for an existing remote
|
||||
\ (alias)
|
||||
4 / Amazon S3 Compliant Storage Providers including AWS, Alibaba, ArvanCloud, Ceph, ChinaMobile, Cloudflare, DigitalOcean, Dreamhost, GCS, HuaweiOBS, IBMCOS, IDrive, IONOS, LyveCloud, Leviia, Liara, Linode, Minio, Netease, Petabox, RackCorp, Rclone, Scaleway, SeaweedFS, StackPath, Storj, Synology, TencentCOS, Wasabi, Qiniu and others
|
||||
\ (s3)
|
||||
5 / Backblaze B2
|
||||
\ (b2)
|
||||
6 / Better checksums for other remotes
|
||||
\ (hasher)
|
||||
7 / Box
|
||||
\ (box)
|
||||
8 / Cache a remote
|
||||
\ (cache)
|
||||
9 / Citrix Sharefile
|
||||
\ (sharefile)
|
||||
10 / Combine several remotes into one
|
||||
\ (combine)
|
||||
11 / Compress a remote
|
||||
\ (compress)
|
||||
12 / Dropbox
|
||||
\ (dropbox)
|
||||
13 / Encrypt/Decrypt a remote
|
||||
\ (crypt)
|
||||
14 / Enterprise File Fabric
|
||||
\ (filefabric)
|
||||
15 / FTP
|
||||
\ (ftp)
|
||||
16 / Google Cloud Storage (this is not Google Drive)
|
||||
\ (google cloud storage)
|
||||
17 / Google Drive
|
||||
\ (drive)
|
||||
18 / Google Photos
|
||||
\ (google photos)
|
||||
19 / HTTP
|
||||
\ (http)
|
||||
20 / Hadoop distributed file system
|
||||
\ (hdfs)
|
||||
21 / HiDrive
|
||||
\ (hidrive)
|
||||
22 / ImageKit.io
|
||||
\ (imagekit)
|
||||
23 / In memory object storage system.
|
||||
\ (memory)
|
||||
24 / Internet Archive
|
||||
\ (internetarchive)
|
||||
25 / Jottacloud
|
||||
\ (jottacloud)
|
||||
26 / Koofr, Digi Storage and other Koofr-compatible storage providers
|
||||
\ (koofr)
|
||||
27 / Linkbox
|
||||
\ (linkbox)
|
||||
28 / Local Disk
|
||||
\ (local)
|
||||
29 / Mail.ru Cloud
|
||||
\ (mailru)
|
||||
30 / Mega
|
||||
\ (mega)
|
||||
31 / Microsoft Azure Blob Storage
|
||||
\ (azureblob)
|
||||
32 / Microsoft Azure Files
|
||||
\ (azurefiles)
|
||||
33 / Microsoft OneDrive
|
||||
\ (onedrive)
|
||||
34 / OpenDrive
|
||||
\ (opendrive)
|
||||
35 / OpenStack Swift (Rackspace Cloud Files, Blomp Cloud Storage, Memset Memstore, OVH)
|
||||
\ (swift)
|
||||
36 / Oracle Cloud Infrastructure Object Storage
|
||||
\ (oracleobjectstorage)
|
||||
37 / Pcloud
|
||||
\ (pcloud)
|
||||
38 / PikPak
|
||||
\ (pikpak)
|
||||
39 / Proton Drive
|
||||
\ (protondrive)
|
||||
40 / Put.io
|
||||
\ (putio)
|
||||
41 / QingCloud Object Storage
|
||||
\ (qingstor)
|
||||
42 / Quatrix by Maytech
|
||||
\ (quatrix)
|
||||
43 / SMB / CIFS
|
||||
\ (smb)
|
||||
44 / SSH/SFTP
|
||||
\ (sftp)
|
||||
45 / Sia Decentralized Cloud
|
||||
\ (sia)
|
||||
46 / Storj Decentralized Cloud Storage
|
||||
\ (storj)
|
||||
47 / Sugarsync
|
||||
\ (sugarsync)
|
||||
48 / Transparently chunk/split large files
|
||||
\ (chunker)
|
||||
49 / Union merges the contents of several upstream fs
|
||||
\ (union)
|
||||
50 / Uptobox
|
||||
\ (uptobox)
|
||||
51 / WebDAV
|
||||
\ (webdav)
|
||||
52 / Yandex Disk
|
||||
\ (yandex)
|
||||
53 / Zoho
|
||||
\ (zoho)
|
||||
54 / premiumize.me
|
||||
\ (premiumizeme)
|
||||
55 / seafile
|
||||
\ (seafile)
|
||||
|
||||
```
|
||||
|
||||
|
||||
new
|
||||
|
||||
```txt
|
||||
1 / 1Fichier
|
||||
\ (fichier)
|
||||
2 / Akamai NetStorage
|
||||
\ (netstorage)
|
||||
3 / Alias for an existing remote
|
||||
\ (alias)
|
||||
4 / Amazon S3 Compliant Storage Providers including AWS, Alibaba, ArvanCloud, BizflyCloud, Ceph, ChinaMobile, Cloudflare, Cubbit, DigitalOcean, Dreamhost, Exaba, Fastly, FileLu, FlashBlade, GCS, HCP, Hetzner, HuaweiOBS, IBMCOS, IDrive, ImpossibleCloud, Intercolo, IONOS, Leviia, Liara, Linode, LyveCloud, Magalu, Mega, Minio, Netease, Outscale, OVHcloud, Petabox, Qiniu, Rabata, RackCorp, Rclone, Scaleway, SeaweedFS, Selectel, Servercore, SpectraLogic, Storj, Synology, TencentCOS, US3, Wasabi, Zadara, Zata, Other
|
||||
\ (s3)
|
||||
5 / Backblaze B2
|
||||
\ (b2)
|
||||
6 / Better checksums for other remotes
|
||||
\ (hasher)
|
||||
7 / Box
|
||||
\ (box)
|
||||
8 / Cache a remote
|
||||
\ (cache)
|
||||
9 / Citrix Sharefile
|
||||
\ (sharefile)
|
||||
10 / Cloudinary
|
||||
\ (cloudinary)
|
||||
11 / Combine several remotes into one
|
||||
\ (combine)
|
||||
12 / Compress a remote
|
||||
\ (compress)
|
||||
13 / DOI datasets
|
||||
\ (doi)
|
||||
14 / Drime
|
||||
\ (drime)
|
||||
15 / Dropbox
|
||||
\ (dropbox)
|
||||
16 / Encrypt/Decrypt a remote
|
||||
\ (crypt)
|
||||
17 / Enterprise File Fabric
|
||||
\ (filefabric)
|
||||
18 / FTP
|
||||
\ (ftp)
|
||||
19 / FileLu Cloud Storage
|
||||
\ (filelu)
|
||||
20 / Filen
|
||||
\ (filen)
|
||||
21 / Files.com
|
||||
\ (filescom)
|
||||
22 / Gofile
|
||||
\ (gofile)
|
||||
23 / Google Cloud Storage (this is not Google Drive)
|
||||
\ (google cloud storage)
|
||||
24 / Google Drive
|
||||
\ (drive)
|
||||
25 / Google Photos
|
||||
\ (google photos)
|
||||
26 / HTTP
|
||||
\ (http)
|
||||
27 / Hadoop distributed file system
|
||||
\ (hdfs)
|
||||
28 / HiDrive
|
||||
\ (hidrive)
|
||||
29 / Huawei Drive
|
||||
\ (huaweidrive)
|
||||
30 / ImageKit.io
|
||||
\ (imagekit)
|
||||
31 / In memory object storage system.
|
||||
\ (memory)
|
||||
32 / Internet Archive
|
||||
\ (internetarchive)
|
||||
33 / Internxt Drive
|
||||
\ (internxt)
|
||||
34 / Jottacloud
|
||||
\ (jottacloud)
|
||||
35 / Koofr, Digi Storage and other Koofr-compatible storage providers
|
||||
\ (koofr)
|
||||
36 / Linkbox
|
||||
\ (linkbox)
|
||||
37 / Local Disk
|
||||
\ (local)
|
||||
38 / Mail.ru Cloud
|
||||
\ (mailru)
|
||||
39 / Mega
|
||||
\ (mega)
|
||||
40 / Microsoft Azure Blob Storage
|
||||
\ (azureblob)
|
||||
41 / Microsoft Azure Files
|
||||
\ (azurefiles)
|
||||
42 / Microsoft OneDrive
|
||||
\ (onedrive)
|
||||
43 / OpenDrive
|
||||
\ (opendrive)
|
||||
44 / OpenStack Swift (Rackspace Cloud Files, Blomp Cloud Storage, Memset Memstore, OVH)
|
||||
\ (swift)
|
||||
45 / Oracle Cloud Infrastructure Object Storage
|
||||
\ (oracleobjectstorage)
|
||||
46 / Pcloud
|
||||
\ (pcloud)
|
||||
47 / PikPak
|
||||
\ (pikpak)
|
||||
48 / Pixeldrain Filesystem
|
||||
\ (pixeldrain)
|
||||
49 / Proton Drive
|
||||
\ (protondrive)
|
||||
50 / Put.io
|
||||
\ (putio)
|
||||
51 / QingCloud Object Storage
|
||||
\ (qingstor)
|
||||
52 / Quatrix by Maytech
|
||||
\ (quatrix)
|
||||
53 / Read archives
|
||||
\ (archive)
|
||||
54 / SMB / CIFS
|
||||
\ (smb)
|
||||
55 / SSH/SFTP
|
||||
\ (sftp)
|
||||
56 / Shade FS
|
||||
\ (shade)
|
||||
57 / Sia Decentralized Cloud
|
||||
\ (sia)
|
||||
58 / Storj Decentralized Cloud Storage
|
||||
\ (storj)
|
||||
59 / Sugarsync
|
||||
\ (sugarsync)
|
||||
60 / Transparently chunk/split large files
|
||||
\ (chunker)
|
||||
61 / Uloz.to
|
||||
\ (ulozto)
|
||||
62 / Union merges the contents of several upstream fs
|
||||
\ (union)
|
||||
63 / WebDAV
|
||||
\ (webdav)
|
||||
64 / Yandex Disk
|
||||
\ (yandex)
|
||||
65 / Zoho
|
||||
\ (zoho)
|
||||
66 / iCloud Drive and Photos
|
||||
\ (iclouddrive)
|
||||
67 / premiumize.me
|
||||
\ (premiumizeme)
|
||||
68 / seafile
|
||||
\ (seafile)
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
# rsync
|
||||
- unidirectional sync
|
||||
\# a for archiving(preserving metadata), v for verbose, z for compressing
|
||||
`rsync -avz --delete "$SOURCE/" "$DESTINATION/"`
|
||||
- bidirectional sync but without syncing deletes, only modifiation to file
|
||||
```bash
|
||||
# Function to sync directories
|
||||
sync_directories() {
|
||||
rsync -avu --ignore-existing "$SOURCE/" "$DESTINATION/"
|
||||
}
|
||||
|
||||
sync_directories2() {
|
||||
rsync -avu --ignore-existing "$DESTINATION/" "$SOURCE/"
|
||||
}
|
||||
|
||||
sync_directories
|
||||
sync_directories2
|
||||
```
|
||||
21
joplin notion extension/Web Development/Extras/redlib.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
redlib
|
||||
https://github.com/redlib-org/redlib
|
||||
|
||||
for building boring ssl , use this to aboid installing large clang
|
||||
1. Install a tiny library extractor if you don't have it (this is incredibly lightweight):bash
|
||||
`sudo apt-get install binutils`
|
||||
Use code with caution.
|
||||
2. Download the .deb package file manually without installing its bloated dependencies:bash
|
||||
`apt-get download libclang-14-dev`
|
||||
Use code with caution.
|
||||
3. Extract just the raw files into a local folder:bash
|
||||
`dpkg -x libclang-14-dev*.deb ./mini-clang`
|
||||
Use code with caution.
|
||||
4. Point Rust to that specific folder before compiling Redlib:bash
|
||||
`export LIBCLANG_PATH=$(pwd)/mini-clang/usr/lib/llvm-14/lib/` and
|
||||
`cargo build --release`
|
||||
Use code with caution.
|
||||
Once the build is done, you can delete the mini-clang folder entirely, and your system stays perfectly clean.
|
||||
Did extracting just the raw libclang binary file allow your cargo build command to succeed?
|
||||
|
||||
then `cargo build --release` should be enough
|
||||
48
joplin notion extension/Web Development/Extras/scrcpy.md
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
scrcpy
|
||||
scrcpy demo.mp4 https://small.fileditchstuff.me/s12/qSQYCGYaMlrIBegxchp.mp4
|
||||
[scrcpy-master.zip](../../../_resources/scrcpy-master.zip)
|
||||
|
||||
|
||||
|
||||
- Installation
|
||||
`pacman -S scrcpy` (in extra repo of arch)
|
||||
- Wireless connection
|
||||
https://www.genymotion.com/blog/open-source-project-scrcpy-now-works-wirelessly/
|
||||
Here are the steps:
|
||||
1. Connect the device to the same Wi-Fi as your computer
|
||||
2. Get your device IP address (in Settings → About phone → Status)
|
||||
3. Enable adb over TCP/IP on your device: `adb tcpip 5555`
|
||||
4. Connect to your device: `adb connect DEVICE_IP:5555` (replace DEVICE_IP)
|
||||
5. Unplug your device
|
||||
6. Run scrcpy as usual
|
||||
- Multiple ADB devices
|
||||
Even for a same device there can be more device like if the `otg` is done through usb and mirroring is done through tcpip.
|
||||
Eg: to select thr mirroring after otg is controlled by usb
|
||||
`scrcpy --select-tcpip`
|
||||
- Commands
|
||||
Display and control your Android device on a desktop.
|
||||
More information: https://github.com/Genymobile/scrcpy.
|
||||
|
||||
- Display a mirror of a connected device:
|
||||
`scrcpy`
|
||||
|
||||
- Display a mirror of a specific device based on its ID or IP address (find it under the `adb devices` command):
|
||||
`scrcpy --serial 0123456789abcdef|192.168.0.1:5555`
|
||||
|
||||
- Start display in fullscreen mode:
|
||||
`scrcpy --fullscreen`
|
||||
|
||||
- Rotate the display screen. Each incremental value adds a 90 degree counterclockwise rotation:
|
||||
`scrcpy --rotation 0|1|2|3`
|
||||
|
||||
- Show touches on physical device:
|
||||
`scrcpy --show-touches`
|
||||
|
||||
- Record display screen:
|
||||
`scrcpy --record path/to/file.mp4`
|
||||
|
||||
- Specify the target directory for pushing files to device by drag and drop (non-APK):
|
||||
`scrcpy --push-target path/to/directory`
|
||||
- to use mouse and keyboard of pc in mobile
|
||||
`scrcpy --otg`
|
||||
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
sharing files with torrent
|
||||
https://sentrytwo.com/9070f52d85
|
||||
|
||||
- Links
|
||||
for public trackers
|
||||
https://github.com/ngosang/trackerslist
|
||||
https://www.wikihow.com/Share-Personal-or-Public-Files-Using-uTorrent
|
||||
|
||||
To share your files using a torrent, you will need to create a torrent file and then share that file so others can download your shared content. Here’s a step-by-step guide to get you started:
|
||||
|
||||
### 1. Choose a Torrent Client
|
||||
|
||||
First, you need a BitTorrent client, which is a software application that manages your downloads and uploads using the torrent protocol. Popular clients include qBittorrent, Deluge, and µTorrent. Download and install a client if you haven’t already.
|
||||
|
||||
### 2. Create a Torrent File
|
||||
|
||||
The exact steps may vary slightly depending on your client, but the basic process is as follows:
|
||||
|
||||
1. **Open your BitTorrent client** and look for an option to create a new torrent. This option is typically found under the File menu.
|
||||
|
||||
2. **Select the files or directories** you wish to share. You can usually choose either individual files or entire folders.
|
||||
|
||||
3. **Add trackers**. Trackers are servers that help peers find each other. Many torrents function well with just a few public trackers. You can find lists of free public trackers with a quick online search. Here's a basic format of how you'd input them:
|
||||
|
||||
```
|
||||
http://tracker.example1.com:80/announce
|
||||
http://tracker.example2.org:80/announce
|
||||
```
|
||||
|
||||
4. **Include web seeds if necessary**. Web seeds are URLs where the torrent content is available for download, providing an additional method for peers to download the content. This is optional and primarily used if you expect a lot of download demand with insufficient seeders.
|
||||
|
||||
5. **Set your privacy options**. Most clients allow you to mark a torrent as private, which means it won’t be shared on a Distributed Hash Table (DHT) network. This is optional and depends on your needs.
|
||||
|
||||
6. **Create and save your torrent file**. You’ll be prompted to save a `.torrent` file. Choose a location and save it.
|
||||
7. Also make sure to choose start seeding immediately
|
||||
|
||||
### 3. Share Your Torrent File
|
||||
|
||||
Now you need to get your `.torrent` file out to people:
|
||||
|
||||
- **Upload the .torrent file to a torrent site**. There are many websites where you can upload your torrent for others to download. Note that the legality of this depends on the content and your jurisdiction.
|
||||
|
||||
- **Share the file directly** with others, via email, file-sharing services, or even messaging apps.
|
||||
|
||||
### 4. Seed Your Torrent
|
||||
|
||||
For others to download your files, your BitTorrent client must be open and the downloaded content in the same location as when you created the torrent. This is known as seeding. If you move the files, you must tell your client where the new location is. You should seed for as long as possible to contribute to the torrent's health.
|
||||
|
||||
### Important Considerations
|
||||
|
||||
- **Legal Issues**: Sharing copyrighted content without permission is illegal in many countries. Ensure what you are sharing is legal to distribute.
|
||||
|
||||
- **Security**: Be mindful of sharing personal data or sensitive information accidentally.
|
||||
|
||||
- **ISP Throttling or Blocking**: Some ISPs throttle or block torrent traffic, which can affect your ability to upload or download via torrents.
|
||||
|
||||
By following these steps, you can share your files with others via torrent. Remember, the beauty of torrenting comes from the community's contribution, so seeding is just as important as downloading.
|
||||
50
joplin notion extension/Web Development/Extras/yt-dlp.md
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
yt-dlp
|
||||
https://github.com/yt-dlp/yt-dlp
|
||||
https://ostechnix.com/yt-dlp-tutorial/
|
||||
|
||||
- downloading video in specfic format
|
||||
for highest being 480p use
|
||||
`yt-dlp -f "best[height<=480]" <URL>`
|
||||
Make sure to remove the video from that folder too bcz it wont replace it
|
||||
or
|
||||
`yt-dlp -f "best[height<=480][ext=mp4]" <URL>`
|
||||
most of time there r video only for higher reolution so need to be combine audio and video which yt-dlp will do using ffmpeg
|
||||
`yt-dlp -f "bv*[height<=480][ext=mp4]+ba" https://www.youtube.com/watch?v=RZmHlKpDpUU -o output.mp4`
|
||||
or
|
||||
`yt-dlp -f "bestvideo[height<=720][ext=mp4]+bestaudio[ext=m4a]/best[height<=720][ext=mp4]" "https://www.example.com/video"`
|
||||
`bv+ba` means best video+best audio
|
||||
It will download video only stream of sometimes webm format but with ffmpeg it will convert it to mp4 anyway
|
||||

|
||||

|
||||
- getting video name from playlist
|
||||
`yt-dlp --get-filename -o "%(title)s" <youtube playlist url>`
|
||||
- download all songs from list of url with embeded thumnail too
|
||||
`yt-dlp -x --audio-format mp3 --embed-thumbnail --add-metadata -o "%(title)s.%(ext)s" -a urls.txt`
|
||||
- downloading yt video with cookies from browser
|
||||
use this flag
|
||||
`--cookies-from-browser firefox:xhn2zoyv.default`
|
||||
|
||||
- personal cookies one command
|
||||
```bash
|
||||
yt-dlp -f "bestvideo[height<=720][ext=mp4][vcodec^=avc1]+bestaudio[ext=m4a]/best[height<=720][ext=mp4]" \
|
||||
--write-subs --write-auto-subs --embed-subs --embed-thumbnail --add-metadata \
|
||||
-o "%(title)s.%(ext)s" "https://www.youtube.com/watch?v=QQQUuCydpo0"
|
||||
--cookies-from-browser firefox:iy5sikrq.default-release-1
|
||||
```
|
||||
 l
|
||||
|
||||
for downloading audio
|
||||
`yt-dlp -x --audio-format mp3 playlistURL`
|
||||
eg
|
||||
`yt-dlp -x --audio-format mp3 --write-subs --write-auto-subs --embed-subs --embed-thumbnail --add-metadata -o "%(title)s.%(ext)s" "https://m.youtube.com/playlist?list=OLAK5uy_lEekRFbRdvpkPx6orDy3HEVBzTHbC75qg" -t sleep
|
||||
`
|
||||
|
||||
for subtitles download
|
||||
`yt-dlp --write-subs --skip-download --sub-lang en -o "%(title)s.%(ext)s" "https://youtube.com/watch?v=123" -t sleep`
|
||||
|
||||
**vpn**
|
||||
1. when using vpn add `-4` to use ipv4 and will help with faster download.
|
||||
2. also your ip will be flagged so better use `-t sleep`
|
||||
|
||||
when downloading hige playlist or channels make sure to use
|
||||
`yt-dlp --download-archive archive.txt "URL"` to avoid downloading same videos again
|
||||
212
joplin notion extension/Web Development/Flutter/Coding.md
Normal file
|
|
@ -0,0 +1,212 @@
|
|||
Coding
|
||||
|
||||
Tree of widgets
|
||||
- Widgets can be specified as `Widgetname(fieldname : text or Widgetname(...))`
|
||||
```dart
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// This method is rerun every time setState is called, for instance as done
|
||||
// by the _incrementCounter method above.
|
||||
//
|
||||
// The Flutter framework has been optimized to make rerunning build methods
|
||||
// fast, so that you can just rebuild anything that needs updating rather
|
||||
// than having to individually change instances of widgets.
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
// TRY THIS: Try changing the color here to a specific color (to
|
||||
// Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
|
||||
// change color while the other colors stay the same.
|
||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
||||
// Here we take the value from the MyHomePage object that was created by
|
||||
// the App.build method, and use it to set our appbar title.
|
||||
title: Text(widget.title),
|
||||
),
|
||||
body: Center(
|
||||
// Center is a layout widget. It takes a single child and positions it
|
||||
// in the middle of the parent.
|
||||
child: Column(
|
||||
// Column is also a layout widget. It takes a list of children and
|
||||
// arranges them vertically. By default, it sizes itself to fit its
|
||||
// children horizontally, and tries to be as tall as its parent.
|
||||
//
|
||||
// Column has various properties to control how it sizes itself and
|
||||
// how it positions its children. Here we use mainAxisAlignment to
|
||||
// center the children vertically; the main axis here is the vertical
|
||||
// axis because Columns are vertical (the cross axis would be
|
||||
// horizontal).
|
||||
//
|
||||
// TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint"
|
||||
// action in the IDE, or press "p" in the console), to see the
|
||||
// wireframe for each widget.
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
const Text(
|
||||
'You have pushed this button this many times',
|
||||
),
|
||||
Text(
|
||||
'$_counter',
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: _incrementCounter,
|
||||
tooltip: 'Increment',
|
||||
child: const Icon(Icons.add),
|
||||
), // This trailing comma makes auto-formatting nicer for build methods.
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
**example to show some features and widgets**
|
||||
```dart
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
void main() {
|
||||
// runApp(const MyApp());
|
||||
runApp(const MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
const MyApp({super.key});
|
||||
|
||||
// This widget is the root of your application.
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'Flutter Demo',
|
||||
theme: ThemeData(
|
||||
// This is the theme of your application.
|
||||
//
|
||||
// TRY THIS: Try running your application with "flutter run". You'll see
|
||||
// the application has a purple toolbar. Then, without quitting the app,
|
||||
// try changing the seedColor in the colorScheme below to Colors.green
|
||||
// and then invoke "hot reload" (save your changes or press the "hot
|
||||
// reload" button in a Flutter-supported IDE, or press "r" if you used
|
||||
// the command line to start the app).
|
||||
//
|
||||
// Notice that the counter didn't reset back to zero; the application
|
||||
// state is not lost during the reload. To reset the state, use hot
|
||||
// restart instead.
|
||||
//
|
||||
// This works for code too, not just values: Most code changes can be
|
||||
// tested with just a hot reload.
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
||||
useMaterial3: true,
|
||||
),
|
||||
home: const MyHomePage(title: 'Flutter Demo Home Page'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class MyHomePage extends StatefulWidget {
|
||||
const MyHomePage({super.key, required this.title});
|
||||
|
||||
// This widget is the home page of your application. It is stateful, meaning
|
||||
// that it has a State object (defined below) that contains fields that affect
|
||||
// how it looks.
|
||||
|
||||
// This class is the configuration for the state. It holds the values (in this
|
||||
// case the title) provided by the parent (in this case the App widget) and
|
||||
// used by the build method of the State. Fields in a Widget subclass are
|
||||
// always marked "final".
|
||||
|
||||
final String title;
|
||||
|
||||
@override
|
||||
State<MyHomePage> createState() => _MyHomePageState();
|
||||
}
|
||||
|
||||
class _MyHomePageState extends State<MyHomePage> {
|
||||
int _counter = 0;
|
||||
|
||||
void _incrementCounter() {
|
||||
setState(() {
|
||||
// This call to setState tells the Flutter framework that something has
|
||||
// changed in this State, which causes it to rerun the build method below
|
||||
// so that the display can reflect the updated values. If we changed
|
||||
// _counter without calling setState(), then the build method would not be
|
||||
// called again, and so nothing would appear to happen.
|
||||
_counter++;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// This method is rerun every time setState is called, for instance as done
|
||||
// by the _incrementCounter method above.
|
||||
//
|
||||
// The Flutter framework has been optimized to make rerunning build methods
|
||||
// fast, so that you can just rebuild anything that needs updating rather
|
||||
// than having to individually change instances of widgets.
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
// TRY THIS: Try changing the color here to a specific color (to
|
||||
// Colors.amber, perhaps?) and trigger a hot reload to see the AppBar
|
||||
// change color while the other colors stay the same.
|
||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
||||
// Here we take the value from the MyHomePage object that was created by
|
||||
// the App.build method, and use it to set our appbar title.
|
||||
title: Center(
|
||||
child: Text(widget.title),
|
||||
)),
|
||||
body: Center(
|
||||
child: Container(
|
||||
// constraints: const BoxConstraints(
|
||||
// maxWidth: 200,
|
||||
// maxHeight: 300,
|
||||
// ),
|
||||
// mainAxisSize: ,
|
||||
width: 200,
|
||||
// alignment:
|
||||
// width: EdgeInsets.only(left: 114),
|
||||
child: Center(
|
||||
// widthFactor: 100.0,
|
||||
child: Card(
|
||||
// Center is a layout widget. It takes a single child and positions it
|
||||
// in the middle of the parent.
|
||||
color: const Color.fromRGBO(30, 190, 30, 0.1),
|
||||
// color : 'green',
|
||||
// margin: EdgeInsets.all(114.0),
|
||||
child: Row(
|
||||
// Column is also a layout widget. It takes a list of children and
|
||||
// arranges them vertically. By default, it sizes itself to fit its
|
||||
// children horizontally, and tries to be as tall as its parent.
|
||||
//
|
||||
// Column has various properties to control how it sizes itself and
|
||||
// how it positions its children. Here we use mainAxisAlignment to
|
||||
// center the children vertically; the main axis here is the vertical
|
||||
// axis because Columns are vertical (the cross axis would be
|
||||
// horizontal).
|
||||
//
|
||||
// TRY THIS: Invoke "debug painting" (choose the "Toggle Debug Paint"
|
||||
// action in the IDE, or press "p" in the console), to see the
|
||||
// wireframe for each widget.
|
||||
// mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: <Widget>[
|
||||
const Text(
|
||||
'Is it nice?',
|
||||
),
|
||||
Text(
|
||||
'$_counter',
|
||||
style: Theme.of(context).textTheme.headlineMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
)))),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: _incrementCounter,
|
||||
tooltip: 'Increment',
|
||||
child: const Icon(Icons.add),
|
||||
), // This trailing comma makes auto-formatting nicer for build methods.
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||

|
||||

|
||||
125
joplin notion extension/Web Development/Flutter/Dart/Basics 2.md
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
Basics 2
|
||||
|
||||
**for-in loop and foreach loop** : used with collections
|
||||
```dart
|
||||
void main() {
|
||||
var no = [1, 2, 3]; // no here is list which is a collection
|
||||
|
||||
// For-in loop
|
||||
for (var x in no) {
|
||||
print(x);
|
||||
}
|
||||
|
||||
// foreach
|
||||
no.forEach((n) => print(n));
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**Collections**
|
||||
- Even if we dont mention collection name and use var instead then due to type inference variable will be converted to that collection.
|
||||
- List can contain values of different data type. To make sure list contains values of one datatype only, use this `List<datatype>` . eg : `List<String>`
|
||||
- To make list immutable use const keyword before list.
|
||||
- When we assign a list to other variable reference is copied. so to make a deep copy use spread operator
|
||||
```dart
|
||||
void main() {
|
||||
// List
|
||||
|
||||
List name = ['Rishav', 'Ramesh', 10];
|
||||
name[1] = 'Suresh';
|
||||
|
||||
print(name); // outputs : [Rishav, Suresh, 10]
|
||||
|
||||
for (var i in name) {
|
||||
print(i);
|
||||
}
|
||||
|
||||
List<String> name2 = ['Rishav', 'Bharghav'];
|
||||
print(name2);
|
||||
|
||||
List name3 = const ['Rishav', 'Raghav'];
|
||||
name3[1] = 'as'; // will give error : Cannot modify an unmodifiable list
|
||||
print(name3);
|
||||
|
||||
var name4 = name; // shallow copy
|
||||
var name5 = [...name]; //deep copy
|
||||
name[2] = 12;
|
||||
|
||||
print('name4: $name4'); // Output: name4: [Rishav, Suresh, 12]
|
||||
print('name5: $name5'); // Output: name5: [Rishav, Suresh, 10]
|
||||
|
||||
// Sets
|
||||
|
||||
Set elements = {'hydrogen', 'oxygen', 'hydrogen'};
|
||||
|
||||
print(elements); // Output: {hydrogen, oxygen}
|
||||
print(elements.runtimeType); // Output: _Set<dynamic>
|
||||
|
||||
// ways to make set con
|
||||
var elements2 = <String>{};
|
||||
Set<String> elements3 = {};
|
||||
// both elements2 and elements3 have same runtimeType
|
||||
print(elements3.runtimeType); // Output: _Set<String>
|
||||
|
||||
// Maps
|
||||
|
||||
var elements4 = {};
|
||||
print(elements4.runtimeType); // Output: _Map<dynamic, dynamic>
|
||||
|
||||
var student = {'name': 'Rishav', 'age': 20, 'email': 'rishav@email.com'};
|
||||
print(student.runtimeType); // Output: _Map<String, Object>
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**Functions**
|
||||
- dart provides shorthand version of functions too to avoid need for return statment. useful for writing pure functions.
|
||||
- by default arguments are called positional arguments so order of values in arguments is necessary but with named arguments we can change the order as we have to provide name ie parameter variable at left side.
|
||||
- there are anonymous functions too like in js
|
||||
```dart
|
||||
void main() {
|
||||
// Functions
|
||||
print(sum('Rishav', ' Kumar')); //Output: Rishav Kumar
|
||||
print(sum2(1, 2)); //Output: 3
|
||||
print(sum3(n2: 'Kumar', n1: 'Rishab')); //Output: RishabKumar
|
||||
}
|
||||
|
||||
|
||||
|
||||
dynamic sum(var n1, var n2) {
|
||||
return n1 + n2;
|
||||
}
|
||||
|
||||
// anonymous function
|
||||
var f=(){
|
||||
return 2;
|
||||
};
|
||||
or
|
||||
var f=()=> 2;
|
||||
|
||||
// positional arguments
|
||||
dynamic sum2(var n1, var n2) => n1 + n2;
|
||||
// named arguments
|
||||
dynamic sum3({var n1, var n2}) => n1 + n2;
|
||||
|
||||
```
|
||||
|
||||
|
||||
**More about Lists**
|
||||
```dart
|
||||
void main(){
|
||||
List<Map<String, Object>> list = [
|
||||
{'string': 'Strength', 'amount': 3},
|
||||
{'string': 'Sugar', 'amount': 3}
|
||||
];
|
||||
|
||||
List<Object?> lis= list.map((e)=> e["string"] ).toList();
|
||||
|
||||
print(lis);
|
||||
print(list.map((e)=> e["string"] ));
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,288 @@
|
|||
Basics 3 Classes
|
||||
|
||||
**Classes and Objects**
|
||||
- in dart there is no constructor overloading so instead named constructor have to be used.
|
||||
```dart
|
||||
class Point {
|
||||
int? x;
|
||||
int? y;
|
||||
|
||||
// Default constructor
|
||||
Point() {
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
// named constructor
|
||||
Point.paramed(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
// String interpolation
|
||||
void printData() => print('$x + $y');
|
||||
|
||||
// functions
|
||||
final void Function() onPressed;
|
||||
}
|
||||
|
||||
void main() {
|
||||
Point p = Point();
|
||||
print(p.x);
|
||||
|
||||
Point p2 = Point.paramed(2, 3);
|
||||
print(p2.x);
|
||||
|
||||
p.printData();
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
**Classes and enums**
|
||||
- Intead of initializing data members inside block of constructor we can define them in initializer list too as it improves performance too
|
||||
- we cant use some operators bcz of some null safety measures introdued in dart so use like this `assert(x!=null && x > 0)`
|
||||
- For Getter and setters , we have keywords too
|
||||
```dart
|
||||
class Point {
|
||||
int? x;
|
||||
int? y;
|
||||
|
||||
// Default constructor
|
||||
Point() {
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
// named constructor
|
||||
Point.paramed(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
// or
|
||||
Point.paramed2(this.x, this.y);
|
||||
// or
|
||||
|
||||
Point.paramed3(this.x, this.y) : assert(x != null && x > 0) {
|
||||
printData();
|
||||
}
|
||||
|
||||
Point.fromMap(Map<String, int> map) {
|
||||
this.x = map['x'];
|
||||
this.y = map['y'];
|
||||
}
|
||||
|
||||
Point.fromMap2(Map<String, int> map)
|
||||
: x = map['x'],
|
||||
y = map['y'] {
|
||||
printData();
|
||||
}
|
||||
|
||||
// String interpolation
|
||||
void printData() => print('$x + $y');
|
||||
|
||||
void printData2() {
|
||||
print('$x - $y');
|
||||
}
|
||||
|
||||
// getters
|
||||
int? get pointX => this.x;
|
||||
int? get pointY => this.y;
|
||||
|
||||
Map<String, int?> get getMap => <String, int?>{
|
||||
'x': this.x,
|
||||
'y': this.y,
|
||||
};
|
||||
|
||||
// setters
|
||||
set setX(int x) => this.x = x;
|
||||
}
|
||||
|
||||
void main() {
|
||||
Point p = Point();
|
||||
print(p.x);
|
||||
|
||||
Point p2 = Point.paramed(2, 3);
|
||||
print(p2.x);
|
||||
|
||||
p.printData();
|
||||
p.printData2();
|
||||
|
||||
Point p3 = Point.fromMap(<String, int>{
|
||||
'x': 10,
|
||||
'y': 20,
|
||||
});
|
||||
|
||||
p3.printData();
|
||||
|
||||
Point p4 = Point.fromMap2(<String, int>{
|
||||
'x': 10,
|
||||
'y': 20,
|
||||
});
|
||||
|
||||
print(p3.pointX);
|
||||
print(p3.pointY);
|
||||
print(p3.getMap);
|
||||
|
||||
p.setX = 500;
|
||||
p.printData();
|
||||
}
|
||||
```
|
||||
Enums
|
||||
- Enum is special variable which contains fixed number of constant values
|
||||
```dart
|
||||
enum PaymentStatus { notPaid,paid };
|
||||
|
||||
void main() {
|
||||
final status = PaymentStatus.notPaid;
|
||||
|
||||
switch (status) {
|
||||
case PaymentStatus.notPaid:
|
||||
print(1);
|
||||
break;
|
||||
default:
|
||||
8;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**Exceptional Handling**
|
||||
- Infinity is a constant which is of double type
|
||||
- To avoid typecasting automatically use tilt symbol before operator. eg : `var c2 = a ~/ b`
|
||||
- Multiple catch can be used too for different types of exception too using `on <ExceptionName>`
|
||||
```dart
|
||||
// Custom Exception
|
||||
class AgeException implements Exception {
|
||||
String errMsg() => 'Age cannot be less than zero';
|
||||
}
|
||||
|
||||
void main() {
|
||||
print('programming knowledge');
|
||||
|
||||
try {
|
||||
var a = 10;
|
||||
var b = 0;
|
||||
var c1 = a / b; // Output : Infinity
|
||||
// var c2 = a ~/
|
||||
// b; // Will give Error for unhandled exception : IntegerDivisionByZeroException
|
||||
print('c1: $c1');
|
||||
// print('c2: $c2');
|
||||
|
||||
var s = [1, 2, 3, 4];
|
||||
print(s[2]);
|
||||
|
||||
var age = -10;
|
||||
if (age < 0) {
|
||||
throw AgeException();
|
||||
}
|
||||
} on AgeException catch (e) {
|
||||
print(e.errMsg());
|
||||
} on IntegerDivisionByZeroException catch (e) {
|
||||
print('Division of zero isnt possible: ${e.message}');
|
||||
} catch (e) {
|
||||
print('Another catch block');
|
||||
} finally {
|
||||
print('always executed');
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
Async and await
|
||||
- Future is just like promise in javascript and contains result of asyncronous operation which have 2 states ie completed and uncompleted. and if completed then its data is either some value or error.
|
||||
```dart
|
||||
Future<void> fetchUserData() {
|
||||
return Future.delayed(Duration(seconds: 2), () => print('Data'));
|
||||
}
|
||||
|
||||
void main() {
|
||||
fetchUserData();
|
||||
print('Fetching user data');
|
||||
}
|
||||
```
|
||||
- async functions always returns Future datatype. async keyword will always be between closing parenthesis and opening curly braces
|
||||
- If we dont use await or then we will get instance of the future not the result. if we use then it will assign callback for the result and switch to next line and if we use await then it will wait for result then move to next line.
|
||||
```dart
|
||||
Future<String> fetchUserData() {
|
||||
return Future.delayed(Duration(seconds: 2), () => 'Data');
|
||||
}
|
||||
|
||||
Future<String> fetchUserData2() {
|
||||
return Future.delayed(Duration(seconds: 4), () => 'Data2');
|
||||
}
|
||||
|
||||
Future<String> userMsg() async {
|
||||
var data = await fetchUserData();
|
||||
return '$data';
|
||||
}
|
||||
|
||||
Future<String> userMsg2() async {
|
||||
var data = await fetchUserData2();
|
||||
return '$data';
|
||||
}
|
||||
|
||||
void main() async {
|
||||
print('Fetching');
|
||||
|
||||
// total time will be of 6s
|
||||
print(await userMsg());
|
||||
print(await userMsg2());
|
||||
|
||||
// total time will be of 4s
|
||||
userMsg().then((value) => print(value));
|
||||
userMsg2().then((value) => print(value));
|
||||
|
||||
// their output will be "Instance of 'Future<String>' "
|
||||
print(userMsg());
|
||||
print(userMsg2());
|
||||
}
|
||||
```
|
||||
|
||||
**Functions**
|
||||
In Dart, `function` (lowercase 'f') refers to a specific, named block of code that performs a task. `Function` (uppercase 'F') refers to the general *type* of functions. Think of it like the difference between a specific car (e.g., a "Honda Civic") and the general concept of a "car."
|
||||
|
||||
Here's a breakdown:
|
||||
|
||||
**1. `function` (lowercase):**
|
||||
|
||||
* Represents a named, callable block of code.
|
||||
* Used when defining or calling a specific function.
|
||||
|
||||
```dart
|
||||
// Defining a function called 'myFunction'
|
||||
void myFunction() {
|
||||
print('Hello from myFunction');
|
||||
}
|
||||
|
||||
// Calling the function
|
||||
myFunction(); // Output: Hello from myFunction
|
||||
```
|
||||
|
||||
**2. `Function` (uppercase):**
|
||||
|
||||
* Represents the function type itself.
|
||||
* Used to declare variables, parameters, or return types that can hold any function, regardless of its specific signature (parameters and return type).
|
||||
|
||||
```dart
|
||||
// Declaring a variable that can hold any function
|
||||
Function myCallback;
|
||||
|
||||
// Assigning a function to the variable
|
||||
myCallback = myFunction; // Assigning the 'myFunction' function
|
||||
```
|
||||
|
||||
|
||||
Regex
|
||||
```dart
|
||||
import 'dart:core';
|
||||
|
||||
void main() {
|
||||
final exp=RegExp(r'/(.+)\..+$');
|
||||
print(exp.firstMatch('a/jk.mp')!.group(1)); // jk
|
||||
print(exp.firstMatch('a/jk.mp')); // true
|
||||
}
|
||||
|
||||
```
|
||||
160
joplin notion extension/Web Development/Flutter/Dart/Basics.md
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
Basics
|
||||
|
||||
- hello world program
|
||||
```dart
|
||||
void main() {
|
||||
print('hello world');
|
||||
}
|
||||
|
||||
```
|
||||
- data types
|
||||
primitive:
|
||||
int, float,double, char, string, bool
|
||||
example
|
||||
```dart
|
||||
void main() {
|
||||
String v = 'Rishav';
|
||||
print(v);
|
||||
}
|
||||
```
|
||||
dynamic : those who can contain any data type
|
||||
var keyword
|
||||
```dart
|
||||
void main() {
|
||||
var v = 'Rishav';
|
||||
var v1 = 10;
|
||||
var v2 = 80.12;
|
||||
print(v);
|
||||
print(v1);
|
||||
print(v2);
|
||||
}
|
||||
|
||||
```
|
||||
dynamic keyword
|
||||
unlike var whose datatype is fixed when assigned, in dynamic, datatype can be changed anytime
|
||||
|
||||
const keyword : once value assigned, it cant be changed
|
||||
|
||||
late keyword is non nullable and initialization will take place later and till then it wont recieve null and wait for its value.
|
||||
```dart
|
||||
import 'dart:io';
|
||||
|
||||
void main() {
|
||||
const v = 'Rishav';
|
||||
var v1;
|
||||
v1 = stdin.readLineSync(); // input 12
|
||||
dynamic v2 = 80.12;
|
||||
v2 = stdin.readLineSync(); //input asd (a string)
|
||||
print("Value of v is $v");
|
||||
print(v1);
|
||||
print(v2);
|
||||
}
|
||||
|
||||
```
|
||||
**Note** : In case of var and const , when we assign value, that value will be assigned during compile time so in future if that assign value (which maybe time or some value from api which can be changed) then in that case dynamic can be used to assign value at run time.
|
||||
|
||||
final and const keyword are also similar but in case of objects(arrays) if const is used array is immutable too(means elements inside array cant be changed)
|
||||
- comments
|
||||
```dart
|
||||
// inline comment
|
||||
/*
|
||||
*
|
||||
* blocks of code
|
||||
*/
|
||||
|
||||
/// documentation
|
||||
```
|
||||
- operators and other logical statements
|
||||
if/else,switch,for , while , do-while loop and all operators even ternary are C like
|
||||
|
||||
|
||||
|
||||
|
||||
**Type casting**
|
||||
```dart
|
||||
void main() {
|
||||
// string to integer
|
||||
var one = int.parse('1');
|
||||
assert(one == 1);
|
||||
|
||||
one += 10;
|
||||
|
||||
print('one: $one');
|
||||
|
||||
//integer to string
|
||||
var oneString = 1.toString();
|
||||
oneString += 'Rishav';
|
||||
print('oneString: ' + oneString);
|
||||
|
||||
// decimal to string
|
||||
var oneString2 = 3.1234.toString();
|
||||
var oneString2D = 3.1234.toStringAsFixed(2);
|
||||
assert(oneString2D == '3.12');
|
||||
|
||||
print('oneString2D: ' + oneString2D);
|
||||
|
||||
if (oneString2D == '3.12')
|
||||
print('correct');
|
||||
else {
|
||||
print('incorrect');
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**Null aware operators**
|
||||
Without null aware operator
|
||||
```dart
|
||||
class Num {
|
||||
var num = 10;
|
||||
}
|
||||
|
||||
void main() {
|
||||
// var n = Num();
|
||||
var n;
|
||||
int no = 0;
|
||||
|
||||
if (n != null) {
|
||||
no = n.num;
|
||||
}
|
||||
|
||||
// print(n) // if var n = Num() then output : Instance of 'Num'
|
||||
// print(no) if var n = Num() then output : 10
|
||||
print(n); // output : null
|
||||
print(no); // output : 0
|
||||
}
|
||||
|
||||
```
|
||||
With null aware operator
|
||||
```dart
|
||||
void main() {
|
||||
// var n = Num();
|
||||
var n;
|
||||
int? no = 0;
|
||||
|
||||
// if (n != null) {
|
||||
// no = n.num;
|
||||
// }
|
||||
|
||||
no = n?.num;
|
||||
|
||||
// print(n) // if var n = Num() then output : Instance of 'Num'
|
||||
// print(no) if var n = Num() then output : 10
|
||||
print(n); // output : null
|
||||
print(no); // output : null
|
||||
}
|
||||
```
|
||||
In case of n being null if we dont want to assign null to `no` of n is null and instead some assign other v
|
||||
`no = n?.num ?? 0;`
|
||||
|
||||
for directly assigning value to a variable whose value is null use `??=`
|
||||
```dart
|
||||
// ??=
|
||||
void main() {
|
||||
int? no;
|
||||
|
||||
print(no ??= 100); // outputs : 100
|
||||
print(no); // outputs : 100
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
Commands
|
||||
|
||||
- there r two ways to execute code
|
||||
`dart main.dart` : directly runs code. useful for quick and single dart file
|
||||
`dart run main.dart` : useful for running a project with lot of other dependencies specified in `pubspec.yaml` file
|
||||
- dart uses AOT(Ahead Of Time) compiler to create executable and jit(Just In Time) interpreter to run code directly which means features like hot reload can be used
|
||||
`dart run main.dart` : jit interpreter
|
||||
`dart compile exe main.dart -o output` and to run this self contained executable called output `./output`
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
- dart null check
|
||||
use this `?.` for conditional thing and use `!.` for null check
|
||||
`ModalRoute.of(context)!.settings.arguments;`
|
||||
81
joplin notion extension/Web Development/Flutter/Extras.md
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
Extras
|
||||
|
||||
- adb
|
||||
- this `-k` flag means it will keep cache and app data so making it more safer
|
||||
- `adb shell`
|
||||
- `adb shell pm list packages` to list installed packages
|
||||
- adb uninstall <package_name> : to uninstall app
|
||||
- `adb shell pm uninstall -k --user 0 <application_name>` to safely install package and not uninstall system istead
|
||||
- `adb shell pm disable-user --user 0 com.miui.android.fashiongallery` to disable for user in case cant be deleted for user
|
||||
|
||||
- video players
|
||||
https://pub.dev/packages/video_player_media_kit/example
|
||||
[media_kit_ex.zip](../../../_resources/media_kit_ex.zip)
|
||||
- pip (Picture in picture)
|
||||
https://pub.dev/packages/flutter_in_app_pip
|
||||
https://pub.dev/packages/pip_view (more scores than upper one)
|
||||
- audio play background
|
||||
https://pub.dev/packages/just_audio_background
|
||||
- some design kits like material design
|
||||
[designs ui.txt](../../../_resources/designs%20ui.txt)
|
||||
- file system
|
||||
- https://docs.flutter.dev/cookbook/persistence/reading-writing-files
|
||||
- in android for accessing external storage need a permission handler to grant storage like this
|
||||
https://pub.dev/packages/permission_handler
|
||||
```dart
|
||||
Future<void> storagePermissions() async {
|
||||
// var status = await Permission.storage.request();
|
||||
var status = await Permission.storage.request();
|
||||
// Permission.storage.request();
|
||||
// var status = await Permission.camera.request();
|
||||
|
||||
if (status.isDenied) {
|
||||
print('storage permission denied');
|
||||
} else if (status.isGranted) {
|
||||
print('storage permission granted');
|
||||
}
|
||||
}
|
||||
```
|
||||
- also in `AndroidManifest.xml` , add following
|
||||
for below android 11
|
||||
```xml
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
```
|
||||
for above andoid 11
|
||||
```xml
|
||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
|
||||
```
|
||||
- by default only photos and videos access is granted so for full grant add following in manifest
|
||||
`<application android:requestLegacyExternalStorage="true">`
|
||||
- forms
|
||||
https://docs.flutter.dev/cookbook/forms/text-input
|
||||
- fetch data from internet
|
||||
https://docs.flutter.dev/cookbook/networking/fetch-data
|
||||
- parsing html
|
||||
https://pub.dev/packages/html
|
||||
[parsing_with_new.dart](../../../_resources/parsing_with_new.dart)
|
||||
- toast in flutter
|
||||
https://docs.flutter.dev/cookbook/design/snackbars
|
||||
- dropdown menu
|
||||
https://api.flutter.dev/flutter/material/DropdownMenu-class.html
|
||||
- to add support for platforms use
|
||||
`flutter create --platforms=ios,android foo` foo here is path of directory containing pubspec.yml
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### Snipppets
|
||||
- popupmenu
|
||||
https://betterprogramming.pub/popup-menu-customization-in-flutter-aa8827f6ce39
|
||||
[popupmenu.dart](../../../_resources/popupmenu.dart)
|
||||
- contextmenu and rendering popmenu anywhere on screen
|
||||
[rightclick_simulation.dart](../../../_resources/rightclick_simulation.dart)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
75
joplin notion extension/Web Development/Flutter/First app.md
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
First app
|
||||
|
||||
- StatelessWidget : base class of all the widget
|
||||
- using const with constructor is recommended if it doesnt change often as it will executed during compile time and this improving performance
|
||||
```dart
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
void main() {
|
||||
runApp(MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
home: Scaffold(
|
||||
body: SelectableText('hello world'),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||

|
||||
|
||||
|
||||
**Appbar**
|
||||
```
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
home: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Programming Knowledge'),
|
||||
backgroundColor: Colors.brown,
|
||||
bottom: PreferredSize(
|
||||
preferredSize: Size(12, 24), child: Icon(Icons.add)),
|
||||
),
|
||||
body: Center(child: Text("Hello World"))));
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
**Column and Rows**
|
||||
- These widgets are similar to flex layout in web development
|
||||
- Column widget is same as flex-column means widgets inside it will be arranged vertically
|
||||
- to make our widgets center both vertically and horizontally use mainAxisAlignment property of column should be `MainAxisAlignment.center` and if Column widget is taking whole screen then crossAxisAlignment property with `CrossAxisAlignment.center` would work. If column is not taking whole width then in the case wrap whole Column Widget as a value of child property of Center Widget
|
||||
- Row widget has similar properties like column with difference is that widgets inside it will be arranged horizontally
|
||||
```dart
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
home: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Programming Knowledge'),
|
||||
backgroundColor: Colors.brown,
|
||||
bottom: PreferredSize(
|
||||
preferredSize: Size(12, 24), child: Icon(Icons.add)),
|
||||
),
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text('my name'),
|
||||
TextButton(
|
||||
child: Text('Press'),
|
||||
onPressed: () => print('Pressed'),
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: Colors.brown,
|
||||
backgroundColor: Colors.grey,
|
||||
shape: LinearBorder())),
|
||||
Text('Programming')
|
||||
]),
|
||||
)));
|
||||
}
|
||||
```
|
||||

|
||||
40
joplin notion extension/Web Development/Flutter/Issues.md
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
Issues
|
||||
|
||||
Maybe these will work
|
||||
- https://xdaforums.com/t/how-to-enable-full-developer-mode-security-install-without-sim-and-wifi.4501749/
|
||||
```txt
|
||||
Many people asked how to do this withoput needing an internet connection, a xiaomi account and the simcard inside the phone.
|
||||
|
||||
I am glad to tell you I found a simple way.
|
||||
|
||||
In MIUI 13:
|
||||
|
||||
Go in developer mode and enable USB debugging (the normal one).
|
||||
Then go to Privacy Protection >> Special permissions
|
||||
From this menu select first Modify System Settings then the small more button at the bottom of the page and tap Show System
|
||||
Scroll down to Shell, tap on it and enable it.
|
||||
Now go back to Privacy Protection >> Special permissions and
|
||||
select Install unknown apps >> More >> Show System
|
||||
Scroll all the way down to Shell andenable Allow from this source
|
||||
```
|
||||
- try this
|
||||
```txt
|
||||
Alternatively
|
||||
"These steps worked for me for Redmi 8 Pro. Follow them in the exact same order.
|
||||
|
||||
Enable Developer Options.
|
||||
|
||||
Settings -> Additional Settings -> Developer Options -> Disable MIUI Optimizations
|
||||
|
||||
Reboot Phone
|
||||
|
||||
Settings -> Additional Settings -> Developer Options -> Allow USB Debugging
|
||||
|
||||
Security (system app) -> Manage apps -> Permissions -> Gear icon (in top right) -> Install via USB (true)
|
||||
|
||||
Reboot Phone
|
||||
|
||||
Settings -> Additional Settings -> Developer Options -> Enable Install via USB
|
||||
"
|
||||
"It will ask for MIUI account. Don't close it and reboot from there. From next run onwards you can install apps either using adb install or via Android Studio."
|
||||
```
|
||||
55
joplin notion extension/Web Development/Flutter/Setup.md
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
Setup
|
||||
https://docs.flutter.dev/get-started/install/linux/desktop
|
||||
|
||||
- download the flutter sdk bundle
|
||||
https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.24.4-stable.tar.xz
|
||||
- Create a folder `~/development/flutter` and extract content of previously downloaded bundle here
|
||||
`tar -xf ~/Downloads/flutter_linux_3.24.4-stable.tar.xz -C ~/development/`
|
||||
- in `.bashrc` add this to add in environment variable PATH
|
||||
`echo 'export PATH="~/development/flutter/bin:$PATH"' >> ~/.bash_profile`
|
||||
- to check if components of flutter development is installed use `flutter doctor`
|
||||
- Create sample flutter app with
|
||||
`flutter create .` at directory where project files will be created
|
||||
- run it with `flutter run`. to run for specific device in case there r multiple device connected to adb or choose desktop one instead of mobiles then
|
||||
`flutter run -d <device_id>`.
|
||||
to list devices use `flutter devices`
|
||||
|
||||
|
||||
**Android development tools setup**
|
||||
- these must be installed
|
||||
```txt
|
||||
Android SDK Platform, API 35.0.1
|
||||
Android SDK Command-line Tools
|
||||
Android SDK Build-Tools
|
||||
Android SDK Platform-Tools
|
||||
Android Emulator
|
||||
```
|
||||
- refer to for installation of android emulator
|
||||
[android-sdk-installation.md](../../../_resources/android-sdk-installation.md) or
|
||||
[Android emulator on linux](../../../joplin%20notion%20extension/Web%20Development/Extras/Android%20emulator%20on%20linux.md)
|
||||
|
||||
|
||||
- enable usb debugging and connect it with usb to check and debug through mobile instead of using emulator
|
||||
- for wifi debugging do this
|
||||
https://stackoverflow.com/questions/4893953/run-install-debug-android-applications-over-wi-fi
|
||||
- Connect the device to the same Wi-Fi as your computer
|
||||
- Get your device IP address (in Settings → About phone → Status)
|
||||
- Enable adb over TCP/IP on your device: `adb tcpip 5555`
|
||||
- Connect to your device: `adb connect DEVICE_IP:5555 (replace DEVICE_IP)`
|
||||
- Unplug your device
|
||||
- To switch the server back to the USB mode, run `adb usb` and back to wireless with `adb tcpip 5555`
|
||||
- to disconnect use
|
||||
`adb disconnect` : this will disconnect all adb devices
|
||||
for specific device use
|
||||
`adb disconnect <device-ip>:<port>`
|
||||
|
||||
for android 11 or newer following can be used too
|
||||
|
||||
1. Ensure both your computer and phone are connected to the same Wi-Fi network.
|
||||
2. On your Android device, go to Settings > System > Developer options and enable Wireless debugging.
|
||||
3. Select Pair device with pairing code to view your device's IP, port number, and a 6-digit code.On your computer, open your terminal and run `adb pair ip_address:port`. (the port which it shows)
|
||||
4. Enter the pairing code when prompted
|
||||
5. now connect too with `adb connect ip_address:port`. this port can be different and will be mentioned there below wireless debugging toggle
|
||||
|
||||
ip_address:port examples
|
||||
`192.168.29.216:37111`
|
||||
23
joplin notion extension/Web Development/Flutter/Snippets.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
Snippets
|
||||
|
||||
- to have ::after like effect
|
||||
```dart
|
||||
Stack(
|
||||
clipBehavior: Clip.none, // Important: Allow content to extend beyond the Stack's bounds
|
||||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: () { /* ... */ },
|
||||
child: Text('Button Text'),
|
||||
),
|
||||
Positioned(
|
||||
bottom: -20, // Adjust this value to control the vertical offset
|
||||
left: 0,
|
||||
right: 0, // For full width
|
||||
child: Text(
|
||||
'Text Below Button',
|
||||
style: TextStyle(fontSize: 12, color: Colors.grey), // Style as needed
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
```
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
Stateless vs Stateful widgets
|
||||
https://pub.dev/packages
|
||||
|
||||
- Stateless widget is similar to pure components and stateful widget is more similar to smart containers in react means Stateless widget is for static widget for no interactivity and stateful contains states too.
|
||||
- To get more widgets we need to add packages. so go to pub.dev site and find
|
||||
- To add toast search this package in pub.dev and read through how to install it. Once you add the line in under dependency then use `flutter pub get` which is similar to `npm i` in nodejs.
|
||||
To avoid entering package info in `pubspec.yaml` directly, `flutter pub add toast` can be used too.
|
||||
```yaml
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
toast: ^0.3.0
|
||||
```
|
||||
- As toast is interactive widget so it must be under Stateful widget's state.
|
||||
```dart
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:toast/toast.dart';
|
||||
|
||||
void main() {
|
||||
runApp(MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(home: MyHomePage());
|
||||
}
|
||||
}
|
||||
|
||||
class MyHomePage extends StatefulWidget {
|
||||
@override
|
||||
State<MyHomePage> createState() => _MyHomeAppState();
|
||||
}
|
||||
|
||||
class _MyHomeAppState extends State<MyHomePage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
ToastContext().init(context);
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Programming Knowledge'),
|
||||
backgroundColor: Colors.brown,
|
||||
bottom: PreferredSize(
|
||||
preferredSize: Size(12, 24), child: Icon(Icons.add)),
|
||||
),
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text('my name'),
|
||||
TextButton(
|
||||
child: Text('Press'),
|
||||
onPressed: () {
|
||||
Toast.show('Toast demo',
|
||||
duration: Toast.lengthLong,
|
||||
gravity: Toast.center,
|
||||
backgroundColor: Colors.cyan,
|
||||
textStyle: TextStyle(color: Colors.black));
|
||||
},
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: Colors.brown,
|
||||
backgroundColor: Colors.grey,
|
||||
shape: LinearBorder())),
|
||||
Text('Programming')
|
||||
]),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
Separation of widgets
|
||||
in `main.dart`, containing root of widget only
|
||||
```dart
|
||||
import 'package:flutter/material.dart';
|
||||
import './myhomepage.dart';
|
||||
|
||||
void main() {
|
||||
runApp(MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(home: MyHomePage());
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
in `myhomepage.dart`
|
||||
```dart
|
||||
import 'package:toast/toast.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class MyHomePage extends StatefulWidget {
|
||||
@override
|
||||
State<MyHomePage> createState() => _MyHomeAppState();
|
||||
}
|
||||
|
||||
class _MyHomeAppState extends State<MyHomePage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
ToastContext().init(context);
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Programming Knowledge'),
|
||||
backgroundColor: Colors.brown,
|
||||
bottom: PreferredSize(
|
||||
preferredSize: Size(12, 24), child: Icon(Icons.add)),
|
||||
),
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text('my name'),
|
||||
TextButton(
|
||||
child: Text('Press'),
|
||||
onPressed: () {
|
||||
Toast.show('Toast demo',
|
||||
duration: Toast.lengthLong,
|
||||
gravity: Toast.center,
|
||||
backgroundColor: Colors.cyan,
|
||||
textStyle: TextStyle(color: Colors.black));
|
||||
},
|
||||
style: TextButton.styleFrom(
|
||||
foregroundColor: Colors.brown,
|
||||
backgroundColor: Colors.grey,
|
||||
shape: LinearBorder())),
|
||||
Text('Programming')
|
||||
]),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
204
joplin notion extension/Web Development/Flutter/States.md
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
States
|
||||
|
||||
- Function setState should be in the callback function which would be responsible to increment the counter defined inside callback function of setState
|
||||
- Instead of using maps of array for loading dynamic widgets we can use for loop too
|
||||
```dart
|
||||
class _MyHomePageState extends State<MyHomePage> {
|
||||
|
||||
int strength = 0;
|
||||
int sugars = 0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
void incrementStats(String name) {
|
||||
setState(() {
|
||||
switch (name) {
|
||||
case 'Strength':
|
||||
strength = (strength + 1) % 5;
|
||||
break;
|
||||
case 'Sugars':
|
||||
sugars = (sugars + 1) % 5;
|
||||
break;
|
||||
}
|
||||
}); // end of setState
|
||||
} // end of incrementStatus function
|
||||
|
||||
body : TextButton( child: Text('$strength - $sugars'),
|
||||
onPressed : ()=>incrementStats('Strength'),
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Control flow**
|
||||
with for loop
|
||||
```dart
|
||||
for (int i = 0; i < int.parse('${e['amount']}'); i++)
|
||||
Image.asset(
|
||||
'${e['imagePath']}',
|
||||
width: 25,
|
||||
color: Colors.brown[200],
|
||||
colorBlendMode: BlendMode.multiply,
|
||||
),
|
||||
```
|
||||
if statement
|
||||
```dart
|
||||
if (int.parse('${e['amount']}') == 0)
|
||||
Text('No ${e['string']}'),
|
||||
```
|
||||
|
||||
|
||||
**Reusable Widgets**
|
||||
in separate file define its class
|
||||
```dart
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class StyledBodyText extends StatelessWidget {
|
||||
const StyledBodyText(this.text, {super.key});
|
||||
|
||||
final String text;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Text(text,
|
||||
style: TextStyle(
|
||||
color: Colors.brown[900],
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 18,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
class StyledButton extends StatelessWidget {
|
||||
const StyledButton({
|
||||
super.key,
|
||||
required this.onPressed,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
final Widget child;
|
||||
final void Function() onPressed;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
backgroundColor: Colors.brown[700],
|
||||
foregroundColor: Colors.white,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(5)),
|
||||
), // roundedRectangleBorder
|
||||
),
|
||||
onPressed: onPressed,
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
in our main file
|
||||
```dart
|
||||
|
||||
// for styled text
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(color: Colors.brown[300]),
|
||||
child: const StyledBodyText('How I like my coffee ..'),
|
||||
// 'You have pushed the button this many times:',
|
||||
),
|
||||
|
||||
// for styled button
|
||||
StyledButton(
|
||||
// style: TextButton.styleFrom(
|
||||
// backgroundColor: Colors.brown,
|
||||
// foregroundColor: Colors.white,
|
||||
// ),
|
||||
child: Icon(Icons.add),
|
||||
onPressed: () => incrementStats('${e['string']}'),
|
||||
),
|
||||
```
|
||||
|
||||
|
||||
**Routes**
|
||||
- https://docs.flutter.dev/cookbook/navigation/named-routes
|
||||
- https://docs.flutter.dev/cookbook/navigation/navigate-with-arguments
|
||||
- Consistent Overlay across multiple routes
|
||||
```dart
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
void main() {
|
||||
runApp(MyApp());
|
||||
}
|
||||
|
||||
class MyApp extends StatefulWidget {
|
||||
@override
|
||||
_MyAppState createState() => _MyAppState();
|
||||
}
|
||||
|
||||
class _MyAppState extends State<MyApp> {
|
||||
bool _showOverlay = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
home: Stack(
|
||||
children: [
|
||||
Navigator(
|
||||
onGenerateRoute: (settings) { // Your routes
|
||||
return MaterialPageRoute(
|
||||
builder: (context) {
|
||||
// Your route/page content
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: Text(settings.name ?? 'Home')),
|
||||
body: Center(child: Text('Page content')),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
if (_showOverlay)
|
||||
Positioned.fill( // Overlay widget
|
||||
child: ColoredBox(
|
||||
color: Colors.black.withOpacity(0.5), // Semi-transparent background
|
||||
child: Center(
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
setState(() => _showOverlay = false);
|
||||
},
|
||||
child: Text('Close Overlay'),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
onGenerateRoute property usecase for routes '/' and '/video'
|
||||
```dart
|
||||
class MyApp extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
onGenerateRoute: (settings) {
|
||||
switch (settings.name) {
|
||||
case '/':
|
||||
return MaterialPageRoute(builder: (context) => HomePage());
|
||||
case '/video':
|
||||
return MaterialPageRoute(builder: (context) => VideoPage());
|
||||
default:
|
||||
return MaterialPageRoute(
|
||||
builder: (context) => Scaffold( // Handle unknown routes
|
||||
body: Center(child: Text('404 - Page Not Found')),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
20
joplin notion extension/Web Development/Flutter/Structure.md
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
Structure
|
||||
https://www.youtube.com/playlist?list=PLS1QulWo1RIa5W8F_XInRJrZLwkLY39oK
|
||||
|
||||
|
||||
- `.dart-tool` : It has basic tool for developer console
|
||||
- `.idea` : basic configurations for android studio. its idea as android studio is fork of intellij idea
|
||||
- `android` : files that supports android functionality like to run, build apps for android.
|
||||
- `build` : hold all output files and generated resources.
|
||||
- `ios` : like android, it targets ios devices
|
||||
- Similarly `linux`, `macos` and `windows` to tareget for respecticve devices
|
||||
- `lib` : Most important folder as it contains source code and contains all dart files
|
||||
- `test` : test cases for project
|
||||
- `.metadata` : contains metadata of project
|
||||
- `analysis_options.yaml` : contains lint rules
|
||||
- `pubspec.lock` : to lock specfic version of dependencies which is generated from `pubspec.yaml` so very important for stability
|
||||
- `pubspec.yaml` : it is configuration file and also one of the most imporant file. it contains configs of third party packages, fonts,images,location,etc
|
||||
|
||||
|
||||
Widgets : Every component in flutter is regarded as widget like text, floating button, heading/label, app bar etc. These all are branches of root widget which is screen which is referred as scafford in flutter. Also all these widgets have their sub widgets too like app bar which have title contains text widget. center widget also have text widget. floating action button has icon widget.
|
||||

|
||||
429
joplin notion extension/Web Development/Flutter/Widgets.md
Normal file
|
|
@ -0,0 +1,429 @@
|
|||
Widgets
|
||||

|
||||
|
||||
**Text**
|
||||
```dart
|
||||
body: Center(
|
||||
child: Text(
|
||||
'Programming Knowledge\nProgramming Knowledge\nProgramming Knowledge\nProgramming Knowledge',
|
||||
maxLines: 3,
|
||||
style: TextStyle(
|
||||
backgroundColor: Colors.red,
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 30,
|
||||
fontStyle: FontStyle.italic),
|
||||
))
|
||||
```
|
||||
|
||||
**RichText**
|
||||
- To provide different styling for indivual words in whole string thats why `TextSpan` Widget is used to enclose word for different styling.
|
||||
```dart
|
||||
body: Center(
|
||||
child: RichText(
|
||||
text: TextSpan(
|
||||
text: 'Programming',
|
||||
style: TextStyle(color: Colors.cyan, fontSize: 15),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: ' Knowledge: ',
|
||||
style: TextStyle(color: Colors.red, fontSize: 30)),
|
||||
TextSpan(
|
||||
text: ' Flutter ',
|
||||
style: TextStyle(color: Colors.green, fontSize: 20)),
|
||||
]),
|
||||
))
|
||||
```
|
||||
|
||||
|
||||
**Buttons**
|
||||
https://docs.flutter.dev/release/breaking-changes/buttons
|
||||
- The FlatButton, RaisedButton and OutlineButton widgets have been replaced by TextButton, ElevatedButton, and OutlinedButton respectively. Each new button class has its own theme: TextButtonTheme, ElevatedButtonTheme, and OutlinedButtonTheme. The original ButtonTheme class is no longer used.
|
||||
|
||||
|
||||
**ElevatedButton**
|
||||
- buttons which are little elevated and when we hold it it gets flat.
|
||||
- in following if onPressed is assingned null then button is disabled and color will be orange instead of red
|
||||
```dart
|
||||
body: Center(
|
||||
child: ElevatedButton(
|
||||
onPressed: () => print('button pressed'),
|
||||
// onPressed: null,
|
||||
child: Icon(Icons.add),
|
||||
style: ElevatedButton.styleFrom(
|
||||
foregroundColor: Colors.white,
|
||||
backgroundColor: Colors.red,
|
||||
elevation: 10,
|
||||
disabledBackgroundColor: Colors.orange,
|
||||
|
||||
)))
|
||||
```
|
||||

|
||||
|
||||
|
||||
OutlinedButton
|
||||
- button having a property related to borders where we can customize it as much as we want
|
||||
- to remove border, style property of BorderSide widget should be `BorderStyle.none`
|
||||
```dart
|
||||
body: Center(
|
||||
child: OutlinedButton(
|
||||
onPressed: () => print('button pressed'),
|
||||
child: Icon(Icons.add),
|
||||
style: OutlinedButton.styleFrom(
|
||||
side: BorderSide(
|
||||
color: Colors.red, width: 5.0, style: BorderStyle.solid),
|
||||
)))
|
||||
```
|
||||

|
||||
|
||||
|
||||
**TextButton**
|
||||
```dart
|
||||
body: Center(
|
||||
child: TextButton(
|
||||
child: Icon(Icons.add),
|
||||
onPressed: () => print('flatbutton pressed'),
|
||||
// onPressed: null,
|
||||
style: TextButton.styleFrom(
|
||||
backgroundColor: Colors.red,
|
||||
foregroundColor: Colors.white,
|
||||
disabledBackgroundColor: Colors.cyan,
|
||||
),
|
||||
onLongPress: () => print('button is pressed for long time'),
|
||||
))
|
||||
```
|
||||

|
||||
|
||||
|
||||
**IconButton**
|
||||
- overlaycolor is a replacement of splash colour. with this there is a animation of overlay translucent color spashing from point of click to others like water
|
||||
- earlier there was tooltip property but now to add tooltip, wrap button inside tooltip.
|
||||
```dart
|
||||
body: Center(
|
||||
child: Tooltip(
|
||||
message: 'description of the button',
|
||||
child: IconButton(
|
||||
icon: Icon(Icons.add),
|
||||
onPressed: () => print('iconbutton pressed'),
|
||||
style: IconButton.styleFrom(
|
||||
backgroundColor: Colors.red,
|
||||
iconSize: 40.0,
|
||||
// splashFactory:
|
||||
overlayColor: Colors.black,
|
||||
padding: EdgeInsets.all(20.0),
|
||||
)),
|
||||
))
|
||||
```
|
||||
|
||||
|
||||
**Ink class**
|
||||
- A convenience widget for drawing images and other decorations on Material widgets so that InkWell and InkResponse splashes will render over them.
|
||||
- As can be seen from the image, the rounded rectange button is actual button and is clickable area and ink is the circle
|
||||
- color property can be either inside Ink widget or under ShapeDecoration but it can be only in one of them and if there is ShapeDecoration then it cannot be under Ink one and only in ShapeDecoration.
|
||||
```dart
|
||||
body: Center(
|
||||
child: Ink(
|
||||
decoration: ShapeDecoration(
|
||||
shape: CircleBorder(),
|
||||
// shape: StarBorder(),
|
||||
// shape: BeveledRectangleBorder(),
|
||||
color: Colors.blue,
|
||||
),
|
||||
// height: 60,
|
||||
width: 115,
|
||||
padding: EdgeInsets.symmetric(vertical: 45),
|
||||
child: IconButton(
|
||||
icon: Icon(Icons.android),
|
||||
onPressed: () => print('iconbutton of ink pressed'))))
|
||||
```
|
||||

|
||||
|
||||
|
||||
FloatingActionButton and extended feature
|
||||
- We can have text and icon both in FloatingActionButton by using Row widget but its not the best case if its content inside is dynamic bcz fixed width needs to be protected.
|
||||
- Colors.colorname ie MaterialColor property also have color darkness numbers too from 100 to 1000. by default its 500. 100 is lightest and 1000 is darkest.
|
||||
- with icon method of ElevatedButton, we can have label too
|
||||
```dart
|
||||
|
||||
body: Center(
|
||||
child: ElevatedButton.icon(
|
||||
onPressed: () => print('ElevatedButton.icon pressed'),
|
||||
icon: Icon(Icons.android),
|
||||
label: Text('Android'),
|
||||
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
|
||||
),
|
||||
), // Center
|
||||
|
||||
floatingActionButton: Container(
|
||||
width: 100,
|
||||
child: FloatingActionButton(
|
||||
onPressed: () => print('FAB pressed'),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
// shape: RoundedRectangleBorder(),
|
||||
// shape: CircleBorder(),
|
||||
shape: StadiumBorder(),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[Icon(Icons.add), Text('Android')],
|
||||
),
|
||||
backgroundColor: Colors.red[600],
|
||||
tooltip: 'ToolTip FAB',
|
||||
),
|
||||
)
|
||||
|
||||
```
|
||||
- For dynamic length and to contain whatever inside it use
|
||||
- inkwell is rectangular area of material that is responsive to touch
|
||||
- material is widget that creates a piece of material.
|
||||
```dart
|
||||
floatingActionButton: Material(
|
||||
color: Colors.red[600], // Set the background color
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(30), // Rounded corners
|
||||
),
|
||||
// shape: CircleBorder(),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: InkWell(
|
||||
onTap: () => print('FAB pressed'),
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 16, vertical: 12), // Adjust padding to fit content
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize
|
||||
.min, // Ensure the row only takes as much space as necessary
|
||||
children: [
|
||||
Icon(Icons.add), // The icon
|
||||
SizedBox(width: 8), // Space between icon and text
|
||||
Text('Android'), // The text
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
```
|
||||
- just like .icon there is .extended for FloatingActionButton to add support for label
|
||||
```dart
|
||||
floatingActionButton: FloatingActionButton.extended(
|
||||
label: Text('Add'),
|
||||
icon: Icon(Icons.add),
|
||||
onPressed: () => print('FAB pressed'),
|
||||
backgroundColor: Colors.red[500],
|
||||
tooltip: 'Tooltip',
|
||||
)
|
||||
```
|
||||

|
||||
|
||||
|
||||
**Container and Padding**
|
||||
- Its a convenience widget that combines multple properties for widgets inside it
|
||||
- The container in Flutter is a parent widget that can contain multiple child widgets and manage them efficiently through width, height, padding, background color, etc.
|
||||
- Container is a Single-child layout widget. But it can have multiple children by using a Multi-child layout widget as its child.
|
||||
https://docs.flutter.dev/development/ui/widgets/layout#Multi-child%20layout%20widgets
|
||||
- in case of BoxConstaints widget, maxheight cant be less that minheight
|
||||
- Padding is a conviennance widget of Container so we can replace Container with Padding if we need to use padding property only
|
||||
|
||||
part 1
|
||||
```dart
|
||||
body: Center(
|
||||
child: Container(
|
||||
// color: Colors.red,
|
||||
padding: const EdgeInsets.only(
|
||||
left: 10.0,
|
||||
right: 20.0,
|
||||
top: 30.0,
|
||||
bottom: 40.0,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.red,
|
||||
|
||||
),
|
||||
child: Text('Programming Knowledge'))),
|
||||
```
|
||||
part 2
|
||||
```dart
|
||||
body: Center(
|
||||
child: Container(
|
||||
// color: Colors.red,
|
||||
// padding: const EdgeInsets.only(
|
||||
// left: 10.0,
|
||||
// right: 20.0,
|
||||
// top: 30.0,
|
||||
// bottom: 40.0,
|
||||
// ),
|
||||
|
||||
constraints: BoxConstraints(maxHeight: 300, minHeight: 100.0),
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
margin: const EdgeInsets.all(20.0),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.red,
|
||||
// shape: BoxShape.circle,
|
||||
shape: BoxShape.rectangle,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Center(
|
||||
child: Text('Programming Knowledge',
|
||||
textAlign: TextAlign.center)))),
|
||||
```
|
||||

|
||||
|
||||
|
||||
**ImageAssets with Frame Builder**
|
||||
- Before using assets we need to configure it in `pubspec.yaml`
|
||||
```yaml
|
||||
# The following section is specific to Flutter packages.
|
||||
flutter:
|
||||
# The following line ensures that the Material Icons font is
|
||||
# included with your application, so that you can use the icons in
|
||||
# the material Icons class.
|
||||
uses-material-design: true
|
||||
|
||||
# To add assets to your application, add an assets section, like this:
|
||||
assets:
|
||||
# - assets/20241110_122305.jpg
|
||||
- assets/
|
||||
```
|
||||
then
|
||||
```dart
|
||||
|
||||
body: Image.asset('assets/20241110_122305.jpg', height: 100.0, width: 50,
|
||||
frameBuilder: (
|
||||
// buildcontext returns parent context
|
||||
BuildContext context,
|
||||
|
||||
// represents image
|
||||
Widget child,
|
||||
|
||||
// frameindex, useful for gif and videos as framerate is changing
|
||||
int? frame,
|
||||
bool wasSynchronouslyLoaded,
|
||||
) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(100),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.red,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
),
|
||||
```
|
||||
- framebuilder is a container around image anyway. in order to not use it do following
|
||||
```dart
|
||||
body: Center(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(100),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.red,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Image.asset(
|
||||
'assets/20241110_122305.jpg',
|
||||
height: 100.0,
|
||||
width: 50,
|
||||
),
|
||||
),
|
||||
),
|
||||
```
|
||||

|
||||
|
||||
|
||||
**All about images**
|
||||
- fit : like in html cover,fill values
|
||||
https://api.flutter.dev/flutter/painting/BoxFit.html
|
||||
```dart
|
||||
body: Container(
|
||||
height: double.infinity,
|
||||
width: double.infinity,
|
||||
child: Image.asset(
|
||||
'assets/20241110_122305.jpg',
|
||||
// fit: BoxFit.cover,
|
||||
// fit: BoxFit.fill,
|
||||
fit: BoxFit.scaleDown,
|
||||
// fit: BoxFit.fitWidth,
|
||||
// fit : BoxFit.fitHeight
|
||||
),
|
||||
),
|
||||
```
|
||||
|
||||
Different fits
|
||||
Fill
|
||||

|
||||
|
||||
Cover and fitWidth
|
||||

|
||||
|
||||
ScaleDown and fitHeight
|
||||

|
||||
|
||||
|
||||
**Expanded Widget**
|
||||
- to take the rest of space
|
||||
```dart
|
||||
Expanded(
|
||||
flex : 2,
|
||||
child : Image.asset('asset/img/coffee_bg.jpg',
|
||||
fit : BoxFit.fitWidth,
|
||||
alignment: Alignment.bottomCenter,
|
||||
)
|
||||
)
|
||||
```
|
||||
https://www.flutterbeads.com/flutter-widget-size-in-percentage/ : for alternatices of expanded
|
||||
|
||||
|
||||
**SingleChildScrollView Widget**
|
||||
- to have scrollbar
|
||||
- in order to use it for partilcular container make sure that container once wrapped by SingleChildScrollView must also be wrapped by expanded something to allow to expand itself for more width/height.
|
||||
```dart
|
||||
body: Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
flex: 1,
|
||||
child: Center(
|
||||
child: Videoplayer(
|
||||
url:
|
||||
'https://user-images.githubusercontent.com/28951144/229373720-14d69157-1a56-4a78-a2f4-d7a134d7c3e9.mp4'),
|
||||
),
|
||||
),
|
||||
lyrics != null
|
||||
? Expanded(
|
||||
flex: 1,
|
||||
child: Container(
|
||||
|
||||
// height: 200,
|
||||
margin:
|
||||
EdgeInsets.symmetric(horizontal: 16, vertical: 32),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
margin: EdgeInsets.only(bottom: 20),
|
||||
child: Text('Lyrics',
|
||||
// textAlign: TextAlign.end,
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.inversePrimary,
|
||||
fontSize: 20,
|
||||
// backgroundColor: Colors.grey,
|
||||
)),
|
||||
),
|
||||
// Scrollable part with a single Text widget
|
||||
Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Text(
|
||||
lyrics,
|
||||
// style: TextStyle(fontSize: 16),
|
||||
),
|
||||
),
|
||||
),
|
||||
])),
|
||||
)
|
||||
: Container(),
|
||||
],
|
||||
),
|
||||
```
|
||||
30
joplin notion extension/Web Development/Flutter/tips.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
tips
|
||||
- for making column elements take whole space horizontally use this
|
||||
`crossAxisAlignment: CrossAxisAlignment.stretch`
|
||||
- in buttons to remove the splash and modify other aspects to it
|
||||
```dart
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
splashFactory: NoSplash.splashFactory,
|
||||
overlayColor: Colors.grey,
|
||||
shape: BeveledRectangleBorder(),
|
||||
),
|
||||
)
|
||||
```
|
||||
- conditional inline widgets
|
||||
[conditional widgets.txt](../../../_resources/conditional%20widgets.txt)
|
||||
- in flutter if there is issue in version imcompability like this
|
||||
```txt
|
||||
Execution failed for task ':path_provider_android:compileDebugJavaWithJavac'.
|
||||
> Could not resolve all files for configuration ':path_provider_android:androidJdkImage'.
|
||||
```
|
||||
then
|
||||
1 .inside android/settings.gradle, change id "com.android.application" to version "8.7.1" apply false
|
||||
image
|
||||
2. in gradle-wraper.properties, change distributionUrl to https://services.gradle.org/distributions/gradle-8.9-all.zip
|
||||
- passing callback from child to parent
|
||||
use callback function as state of parent, pass the function which can change callback by taking to parameter to child and in child widget update the callback function of parent state.
|
||||
eg: `VoidCallback? takeScreenShot;`
|
||||
- sorting files with date modified
|
||||
https://stackoverflow.com/questions/70225891/how-to-sort-list-of-file-in-order-of-latest-to-oldest
|
||||
|
||||
9
joplin notion extension/Web Development/Github/2FA.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
- https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/about-mandatory-two-factor-authentication
|
||||
|
||||
|
||||
I have to make a E2E chat application where users can create a room and invite others. RSA can be used to send text messages easily.
|
||||
|
||||
To send message from user A to users B,C,D and E i need to encrypt my message 4 times for different users using public key of B,C,D and E and these encrypted version of messages to them. Its not a big deal for text.
|
||||
But if i have to encrypt larger files using RSA then i have to make encrypted version of files 4 times for different 4 users and it would be much slower if there are like 100s of users. So a smart way is to instead of encrypting files using RSA, we can encrypt using any symmetric encryption then encrypt the keys using RSA and send it
|
||||
|
||||
Users will get different versions of keys but only 1 encrypted version of that file
|
||||
122
joplin notion extension/Web Development/Github/Basics.md
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
Basics
|
||||
|
||||
- https://www.nobledesktop.com/learn/git/git-branches
|
||||
|
||||
[Git Branches_ List, Create, Switch to, Merge, Push, & Delete (11_2_2023 4_41_42 PM).html](../../../_resources/Git%20Branches_%20List,%20Create,%20Switch%20to,%20Merge,%20Push.html)
|
||||
|
||||
- Branches
|
||||
- If you want to push your code to a different branch of the remote repository on Codeberg, you can specify the branch in the git push command. Here's how you can do it:
|
||||
|
||||
Assuming you have already added the remote repository using a command like:
|
||||
|
||||
|
||||
|
||||
`git remote add origin your-codeberg-repo-url.git`
|
||||
|
||||
You can push your code to a different branch as follows:
|
||||
|
||||
|
||||
|
||||
`git push origin your-local-branch-name:your-remote-branch-name`
|
||||
|
||||
Here's what each part of the command does:
|
||||
|
||||
your-local-branch-name: Replace this with the name of the local branch you want to push. This is the branch that contains the code you want to deploy.
|
||||
|
||||
your-remote-branch-name: Replace this with the name of the branch in the remote repository (on Codeberg) where you want to push your code.
|
||||
|
||||
For example, if you have a local branch called "feature-branch" and you want to push it to a branch named "production" on Codeberg, you would use the following command:
|
||||
|
||||
|
||||
|
||||
`git push origin feature-branch:production`
|
||||
|
||||
This command will push the code from your local "feature-branch" to the "production" branch on the remote repository on Codeberg. Make sure the branch names are accurate to avoid any conflicts or errors.
|
||||
**to change default branch**
|
||||
`git push -u origin --all`
|
||||
|
||||
- undo git add
|
||||
For specific files use
|
||||
`git reset <file>`
|
||||
For all files
|
||||
`git reset HEAD`
|
||||
- diff
|
||||
When using diff and we wanna avoid the changes in whitespace bcz of pretty formatting then use
|
||||
`git diff -w`
|
||||
or
|
||||
` git diff -w --numstat`
|
||||
When using diff filemode ie permissions is different by default in windows and unix machines so when using git diff output can be
|
||||
```text
|
||||
old mode : 100644
|
||||
new mode : 100755
|
||||
```
|
||||
So to fix it use
|
||||
`git config core.filemode false`
|
||||
https://stackoverflow.com/questions/1257592/how-do-i-remove-files-saying-old-mode-100755-new-mode-100644-from-unstaged-cha
|
||||
- pull requests
|
||||
1. after cloning the repo(original one) and cd into it fetch the pull request to branch named 'local-branch-name'. name can be anything.
|
||||
`git fetch origin pull/PR_NUMBER/head:local-branch-name`
|
||||
2. Then switch to `local-branch-name` and check it, if changes are good then merge it by
|
||||
```bash
|
||||
git checkout main # or develop, or another branch
|
||||
git merge local-branch-name
|
||||
```
|
||||
- to list all files tracked by github use `git ls-files`
|
||||
- to push non interactively use this
|
||||
found this, this is the way
|
||||
`git push https://$GIT_USERNAME:$GIT_TOKEN@github.com/username/repo.git`
|
||||
|
||||
|
||||
to have different user and email for repo use this
|
||||
```sh
|
||||
git config user.name "Your Work Name"
|
||||
git config user.email "work@email.com"
|
||||
```
|
||||
|
||||
|
||||
**clearing .git folder**
|
||||
sometimes git folders can become very large. few things to clear is
|
||||
to check issues or dangling blobs(uncommited files/data to repo)
|
||||
`git fsck --full`
|
||||
and to remove dangling blobs
|
||||
`git prune`
|
||||
|
||||
but if it got commited then
|
||||
for untracking
|
||||
```sh
|
||||
git rm -r --cached bin/
|
||||
git rm -r --cached obj/
|
||||
```
|
||||
and for actual removing
|
||||
```sh
|
||||
# using filter branch
|
||||
git filter-branch --force --index-filter \
|
||||
"git rm --cached --ignore-unmatch path/to/bigfile.zip" \
|
||||
--prune-empty --tag-name-filter cat -- --all
|
||||
|
||||
# Clean up refs and gc
|
||||
rm -rf .git/refs/original/
|
||||
git reflog expire --expire=now --all
|
||||
git gc --prune=now --aggressive
|
||||
|
||||
# Force push
|
||||
git push origin --force --all
|
||||
git push origin --force --tags
|
||||
```
|
||||
|
||||
instead of filter branch, this can be used too, though it needs to be installed `pip install git-filter-repo --break-system-packages`
|
||||
```sh
|
||||
git filter-repo --path path/to/bigfile.zip --invert-paths
|
||||
```
|
||||
|
||||
|
||||
**applying patches **
|
||||
|
||||
from a file
|
||||
`git apply --check ytfetch-403-fix.patch`
|
||||
If it doesn't return anything, that's good.
|
||||
then
|
||||
`git apply ytfetch-403-fix.patch`
|
||||
|
||||
create patch with
|
||||
`git diff > my_patch.patch`
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
Multi account with ssh keys on a device
|
||||
https://www.techaddressed.com/tutorials/add-verify-ssh-keys-gitea/
|
||||
|
||||
- Linux
|
||||
The permissions have to be set like this
|
||||
This means that the permissions on that file are also set incorrectly, and can be adjusted with this:
|
||||
|
||||
`sudo chmod 644 ~/.ssh/known_hosts` : it means read and write for user and read for group and others
|
||||
|
||||
Finally, you may need to adjust the directory permissions as well:
|
||||
|
||||
`sudo chmod 755 ~/.ssh` : it means read,write,execute for user, read,execute for group and others
|
||||
|
||||
This should get you back up and running.
|
||||
|
||||
|
||||
|
||||
The keys need to be read-writable only by you:
|
||||
|
||||
`chmod 600 ~/.ssh/id_rsa`
|
||||
|
||||
Alternatively, the keys can be only readable by you (this also blocks your write access):
|
||||
|
||||
`chmod 400 ~/.ssh/id_rsa`
|
||||
|
||||
600 appears to be better in most cases, because you don't need to change file permissions later to edit it. (See the comments for more nuances)
|
||||
|
||||
80
joplin notion extension/Web Development/Github/branches.md
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
branches
|
||||
|
||||
1. suppose there is a problem
|
||||
```txt
|
||||
if i have to make multiple versions of a page and thats where version control like git helps and i use multiple branch for multiple versions of my page.
|
||||
|
||||
so lets say i create a page which has
|
||||
1. blue background
|
||||
2. red foreground
|
||||
|
||||
now i have created a branch v2 which is branched from this earlier master branch
|
||||
now this page have
|
||||
1. black bg
|
||||
2. white fg
|
||||
and few more changes to be done
|
||||
3. rectangle div at center of screen
|
||||
|
||||
and now my boss saw my both version and preferred version 1 ie master branch but master branch is lacking 3rd change
|
||||
so how do i get changes from master branch and also new changes from v2 and create another branch so it have
|
||||
1. master branch properies ie blue bg and red fg and 3rd property ie rectangle div at center of screen
|
||||
```
|
||||
then
|
||||
maybe this will help
|
||||
https://joseewouters.nl/blog/cherry-picking-with-git-in-your-terminal/
|
||||
|
||||
if editing 1st and 2nd property has separate commit named `edit colors` and adding rectangle div have commit named `adding container` then go to v2 and craete a branch from this `git checkout -b v3`
|
||||
Now using rebase
|
||||
`git rebase -i master`
|
||||
this will be the output
|
||||
```txt
|
||||
pick a1b2c3 edit colors
|
||||
pick d4e5f6 adding container
|
||||
|
||||
```
|
||||
change to
|
||||
```txt
|
||||
edit a1b2c3 edit colors
|
||||
pick d4e5f6 adding container
|
||||
|
||||
```
|
||||
now when u save this, it will stop the git to that edit colors commit
|
||||
now do this
|
||||
`git reset HEAD~` ( move back to parent commit of HEAD )
|
||||
as we want to actually dont want edit colors thing to be taken place. as the edit colors commit changes has been applied here so we need to move back to parent commit of HEAD
|
||||
|
||||
now make changes manually here as we r just editing changes of one commit without dealing with others
|
||||
|
||||
now add commits
|
||||
```sh
|
||||
git add file.txt
|
||||
git commit -m "Add center div container"
|
||||
|
||||
```
|
||||
there can be more commits after this and we may not need to add all of them
|
||||
then just do
|
||||
`git rebase --continue`
|
||||
to abort all this in between in case things can get messy use
|
||||
`git rebase --abort`
|
||||
|
||||
above steps have a manual appraoch too bcz changes to be made before staging is still to be done manually.
|
||||
|
||||
more git rebase words
|
||||
```txt
|
||||
Keep commit : pick
|
||||
Modify / split commit : edit
|
||||
Rename commit : reword
|
||||
Combine commits : squash
|
||||
Auto-combine commits : fixup
|
||||
Remove commit : drop
|
||||
Run command : exec
|
||||
```
|
||||
|
||||
in vscode accept combination to merge changes in merge editor or just do it manually after dropping one of commit
|
||||
|
||||
**and maybe this might help**
|
||||
after forking it, keep one branch unchanged to always follow upstream. Periodically sync the fork so the upstream branch is up to date. Periodically merge changes you want to your other branches
|
||||
|
||||
also
|
||||
git rebase implies adding your commits after the other guys'
|
||||
git merge would add their commits after yours
|
||||
42
joplin notion extension/Web Development/Github/codeberg.md
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
- Hosting static pages
|
||||
1. Create a public repository named pages to make the site available at the main subdomain.
|
||||
or
|
||||
|
||||
Create a branch pages in a public repository:
|
||||
`git switch --orphan pages`
|
||||
`git rm --cached -r . `
|
||||
|
||||
2. Push your static content, HTML, style, fonts, images or anything else.
|
||||
3. Access your new website using this link:
|
||||
https://USERNAME.codeberg.page[/REPOSITORY][/@BRANCH]
|
||||
or
|
||||
To use a custom domain, create a file .domains in your repository with the domain name you wish to use.
|
||||
|
||||
Then, add a DNS record for that domain:
|
||||
CNAME [[branch.]repo.]user.codeberg.page.
|
||||
|
||||
Or for apex domains where CNAME doesn't work:
|
||||
ALIAS codeberg.page.
|
||||
TXT [[branch.]repo.]user.codeberg.page
|
||||
|
||||
If ALIAS isn't supported, use A & AAAA instead:
|
||||
A 217.197.91.145
|
||||
AAAA 2001:67c:1401:20f0::1
|
||||
\+ TXT as above
|
||||
|
||||
4. Example: Repo name: https://broSahru.codeberg.page/test/
|
||||
|
||||
- Hosting react pages
|
||||
Deploy build folder manualluy
|
||||
```bash
|
||||
git init
|
||||
git add .
|
||||
git commit -m "Initial build"
|
||||
git remote add origin your-codeberg-repo-url.git
|
||||
git push -u origin master
|
||||
```
|
||||
Also make sure that in package.json there is a field
|
||||
`"homepage" : "https://broSahru.codeberg.page/test"`
|
||||
|
||||
|
||||
|
||||
6
joplin notion extension/Web Development/Github/extras.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
extras
|
||||
|
||||
tips
|
||||
1. go to any project, click on the commit, add .patch in the URL bar and it will most likely show you an email you can message without it looking stupid on github
|
||||
2. to get personal aaccess token go to this url
|
||||
https://github.com/settings/tokens
|
||||
13
joplin notion extension/Web Development/Github/forgejo.md
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
forgejo
|
||||
|
||||
for self hosted instance do this
|
||||
1. get binary from codeberg release page
|
||||
https://codeberg.org/forgejo/forgejo
|
||||
2. create `app.ini` file and have custom port like this
|
||||
```ini
|
||||
[server]
|
||||
HTTP_PORT = 3005
|
||||
```
|
||||
3. finally open this executable while also having path of app.ini file
|
||||
`./forgejo-15.0.3-linux-amd64 --config ./app.ini`
|
||||
4. for overview tab like in github repo needed to be create with name `.profile` instead of username and add README.md there
|
||||
0
joplin notion extension/Web Development/Github/gitlab.md
Normal file
263
joplin notion extension/Web Development/Go/Basics 2.md
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
Basics 2
|
||||
|
||||
Conditions
|
||||
|
||||
if/else if/else are same its just that brackets surrounding conditions are not required. switch case is similar too with extra functionality like multi case
|
||||
|
||||
```go
|
||||
func main() {
|
||||
day := 5
|
||||
|
||||
switch day {
|
||||
case 1,3,5:
|
||||
fmt.Println("Odd weekday")
|
||||
case 2,4:
|
||||
fmt.Println("Even weekday")
|
||||
case 6,7:
|
||||
fmt.Println("Weekend")
|
||||
default:
|
||||
fmt.Println("Invalid day of day number")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Loops
|
||||
like in other language. for iteraing over elements of arrays,slice and map range keyword can be used too. it gives index and value respectively.
|
||||
index may not be used so blank identifiers can be used which is like a black hole. And even if it is used then it means those values wont be used later so it will still generate error so in that case blank identifier can be used too
|
||||
|
||||
|
||||
```go
|
||||
adj := [2]string{"Big", "Tasty"}
|
||||
fruits := [...]string{"Apple", "Orange"}
|
||||
|
||||
for i := 0; i < len(adj); i++ {
|
||||
for j := 0; j < len(fruits); j++ {
|
||||
if adj[i] == "Big" {
|
||||
|
||||
fmt.Println("Big mentioned")
|
||||
}
|
||||
fmt.Println(adj[i], fruits[j])
|
||||
}
|
||||
}
|
||||
|
||||
for i, val := range adj {
|
||||
for j, val2 := range fruits {
|
||||
if val == "Big" {
|
||||
|
||||
fmt.Println("Big mentioned")
|
||||
}
|
||||
fmt.Println(val, val2)
|
||||
// blank identifers
|
||||
_, _ = i, j
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Extras
|
||||
- go functions if needed to be used in other packages then it needed to be capitalized so using Run() instead of run().
|
||||
|
||||
|
||||
|
||||
random number
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand/v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Random integer between 0 and 99
|
||||
num := rand.IntN(100)
|
||||
fmt.Println("Integer (0-99):", num)
|
||||
|
||||
// Random float64 between 0.0 and 1.0
|
||||
floatNum := rand.Float64()
|
||||
fmt.Println("Float (0.0-1.0):", floatNum)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
also
|
||||
```go
|
||||
|
||||
f,err := os.Open(path)
|
||||
|
||||
if err!=nil{
|
||||
return err
|
||||
}
|
||||
|
||||
defer f.Close()
|
||||
|
||||
scanner:= bufio.NewScanner(f)
|
||||
|
||||
|
||||
```
|
||||
NewScanner accepts io.Reader but os.Open outputs *os.File. due to inferfaces handled implicitly so need to 'implement interface' like in java
|
||||
|
||||
|
||||
|
||||
**structs**
|
||||
```go
|
||||
type Message struct {
|
||||
Id string `json:"id"`
|
||||
CreatedTimestamp int64 `json:"createdTimestamp"`
|
||||
Type int `json:"type"`
|
||||
Content string `json:"content"`
|
||||
Reference struct {
|
||||
MessageId string `json:"messageId"`
|
||||
} `json:"reference"`
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
or if null is expected and empty struct is not fine then simply use pointer struct
|
||||
```go
|
||||
type Message struct {
|
||||
Id string `json:"id"`
|
||||
CreatedTimestamp int64 `json:"createdTimestamp"`
|
||||
Type int `json:"type"`
|
||||
Content string `json:"content"`
|
||||
Reference *struct {
|
||||
MessageId string `json:"messageId"`
|
||||
} `json:"reference"`
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
optional fields in struct
|
||||
|
||||
```go
|
||||
type User struct {
|
||||
Name string `json:"name"`
|
||||
Age *int `json:"age,omitempty"` // Optional
|
||||
Active *bool `json:"active,omitempty"` // Optional
|
||||
}
|
||||
```
|
||||
|
||||
for array of struct if we need to distinguish nil and empty slice before go 1.24 then
|
||||
```go
|
||||
Items *[]Product `json:"items,omitempty"`
|
||||
```
|
||||
|
||||
otherwise following will be fine
|
||||
```go
|
||||
Items []Product `json:"items,omitempty"`
|
||||
```
|
||||
|
||||
|
||||
parsing fields of multtiple types
|
||||
https://stackoverflow.com/questions/56394456/unmarshal-json-field-is-int-or-string
|
||||
|
||||
also
|
||||
https://go.dev/play/p/XnQRS8H0tKE
|
||||
```go
|
||||
package main
|
||||
|
||||
import "fmt"
|
||||
|
||||
func foo(x any) {
|
||||
switch v := x.(type) {
|
||||
case int:
|
||||
fmt.Printf("math: x + 2 == %d\n", v+2)
|
||||
case string:
|
||||
fmt.Printf("string: x + def == %s\n", v+"def")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
var x any = 5
|
||||
foo(x)
|
||||
x = "abc"
|
||||
foo(x)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
and maybe with reflects(not recommended)
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func checkEquality(data any) {
|
||||
switch reflect.TypeOf(data).Kind() {
|
||||
case reflect.Int:
|
||||
if data == 1 {
|
||||
fmt.Println("It is equal to 1")
|
||||
} else {
|
||||
fmt.Println("It is not equal to 1")
|
||||
}
|
||||
case reflect.String:
|
||||
if data == "one" {
|
||||
fmt.Println("It is equal to one")
|
||||
} else {
|
||||
fmt.Println("It is not equal to one")
|
||||
}
|
||||
default:
|
||||
fmt.Println("Not a string nor an int")
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
checkEquality("one")
|
||||
checkEquality(1)
|
||||
checkEquality(true)
|
||||
checkEquality(34)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
**error handling**
|
||||
|
||||
|
||||
```go
|
||||
|
||||
err:= json.Unmarshal(data, &config)
|
||||
if err != nil {
|
||||
fmt.Println("Error in reading json")
|
||||
os.Exit(1)
|
||||
}
|
||||
```
|
||||
|
||||
short form of above
|
||||
```go
|
||||
if err:= json.Unmarshal(data, &config); err!=nil{
|
||||
// code for handling error
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
also for equivalent ry catch possibility
|
||||
|
||||
```go
|
||||
func riskyBlock() (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("recovered from panic: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
// --- your code here ---
|
||||
x := 10 / 0 // panics
|
||||
fmt.Println(x) // never reached
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := riskyBlock(); err != nil {
|
||||
fmt.Println("Error:", err)
|
||||
}
|
||||
fmt.Println("Program continues")
|
||||
}
|
||||
```
|
||||
285
joplin notion extension/Web Development/Go/Basics.md
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
Basics
|
||||
|
||||
|
||||
datatypes
|
||||
|
||||
| Spec term | What it covers |
|
||||
|---|---|
|
||||
| **Basic types** (predeclared) | `bool`, `string`, numeric types (`int`, `uint`, `float`, `complex`, `byte`, `rune`) |
|
||||
| **Composite types** (via type literals) | array, struct, pointer, function, interface, slice, map, channel |
|
||||
|
||||
**Variables**
|
||||
|
||||
There are mainly 3 data types ie bool, Numeric (int and float32) and string.
|
||||
|
||||
There are 2 ways to declare a variable
|
||||
|
||||
1. with var keyword
|
||||
`var variablename type = value`(with initial value) or `var variablename type`(with no initial value)
|
||||
2. with `:=` sign
|
||||
`variablename := value ` . data type is assigned with initial value type so there is no way to declare it without initial value. Also this method can be only used inside a function
|
||||
|
||||
eg
|
||||
```go
|
||||
package main
|
||||
import ("fmt")
|
||||
|
||||
func main() {
|
||||
var student1 string = "John" //type is string
|
||||
var student2 = "Jane" //type is inferred
|
||||
x := 2 //type is inferred
|
||||
|
||||
fmt.Println(student1)
|
||||
fmt.Println(student2)
|
||||
fmt.Println(x)
|
||||
}
|
||||
```
|
||||
|
||||
for multiple values
|
||||
```go
|
||||
var a, b, c, d int = 1, 3, 5, 7
|
||||
```
|
||||
or
|
||||
```go
|
||||
var (
|
||||
a int
|
||||
b int = 1
|
||||
c string = "hello"
|
||||
)
|
||||
```
|
||||
|
||||
Similarly there are constants whose value cant be changed and is read-only
|
||||
it dont have that `:=` thing and can be even defined without type
|
||||
|
||||
```go
|
||||
const (
|
||||
A int = 1
|
||||
B = 3.14
|
||||
C = "Hi!"
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
Output functions
|
||||
|
||||
It has `Print`, `Println` and `Printf`
|
||||
```go
|
||||
func main() {
|
||||
var i string = "Hello"
|
||||
fmt.Printf("i has value: %v and type: %T\n", i, i)
|
||||
}
|
||||
```
|
||||
%v and %T are formatting verbs
|
||||
```txt
|
||||
%v Prints the value in the default format
|
||||
%#v Prints the value in Go-syntax format
|
||||
%T Prints the type of the value
|
||||
%% Prints the % sign
|
||||
```
|
||||
|
||||
```go
|
||||
package main
|
||||
import ("fmt")
|
||||
|
||||
func main() {
|
||||
var i = 15.5
|
||||
var txt = "Hello World!"
|
||||
|
||||
fmt.Printf("%v\n", i)
|
||||
fmt.Printf("%#v\n", i)
|
||||
fmt.Printf("%v%%\n", i)
|
||||
fmt.Printf("%T\n", i)
|
||||
|
||||
fmt.Printf("%v\n", txt)
|
||||
fmt.Printf("%#v\n", txt)
|
||||
fmt.Printf("%T\n", txt)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
**Data types**
|
||||
|
||||
1. Integers
|
||||
`int`, `uint` for signed and unsigned integers . Also `int8`, `int16`, ..
|
||||
2. Float
|
||||
```go
|
||||
func main() {
|
||||
var x float64 = 1.7e+308
|
||||
fmt.Printf("Type: %T, value: %v", x, x)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### Arrays
|
||||
|
||||
Syntax
|
||||
```go
|
||||
var array_name = [length]datatype{values} // here length is defined
|
||||
|
||||
// or
|
||||
|
||||
var array_name = [...]datatype{values} // here length is inferred
|
||||
|
||||
// or
|
||||
|
||||
array_name := [length]datatype{values} // here length is defined
|
||||
|
||||
// or
|
||||
|
||||
array_name := [...]datatype{values} // here length is inferred
|
||||
|
||||
```
|
||||
|
||||
eg
|
||||
```go
|
||||
func main() {
|
||||
var arr1 = [3]int{1,2,3}
|
||||
arr2 := [...]int{4,5,6,7,8}
|
||||
// or
|
||||
// declaring a array with no initialization
|
||||
var a [5]int
|
||||
|
||||
fmt.Println(arr1)
|
||||
fmt.Println(arr2)
|
||||
}
|
||||
```
|
||||
|
||||
in case of integer array, if all the elements are not initialized then those remaining ones will be filled with 0.
|
||||
|
||||
To initialize specific elements
|
||||
```go
|
||||
func main() {
|
||||
arr1 := [5]int{1:10,2:40}
|
||||
|
||||
fmt.Println(arr1)
|
||||
|
||||
// to get length of array
|
||||
fmt.Println(len(arr1))
|
||||
}
|
||||
```
|
||||
|
||||
Output
|
||||
`[0 10 40 0 0] `
|
||||
|
||||
|
||||
and to find element position in array
|
||||
`index := slices.Index(myArray[:], target)`
|
||||
and for array of structs
|
||||
```go
|
||||
index := slices.IndexFunc(users[:], func(u User) bool {
|
||||
return u.ID == targetID
|
||||
})
|
||||
```
|
||||
|
||||
**Slices**
|
||||
|
||||
Slices are like arrays and unlike arrays its size can grow or shrink. It has length and capacity thing.
|
||||
|
||||
Syntax
|
||||
```go
|
||||
slice_name := []datatype{values}
|
||||
|
||||
and
|
||||
|
||||
slice_name := make([]type, length, capacity)
|
||||
|
||||
```
|
||||
|
||||
example
|
||||
```go
|
||||
func main() {
|
||||
myslice1 := []int{}
|
||||
fmt.Println(len(myslice1))
|
||||
fmt.Println(cap(myslice1))
|
||||
fmt.Println(myslice1)
|
||||
|
||||
myslice2 := []string{"Go", "Slices", "Are", "Powerful"}
|
||||
fmt.Println(len(myslice2))
|
||||
fmt.Println(cap(myslice2))
|
||||
fmt.Println(myslice2)
|
||||
|
||||
myslice3 := make([]int, 5, 10)
|
||||
}
|
||||
```
|
||||
|
||||
to change or access elements it is same as arrays. To append elemnts use append function
|
||||
`slice_name = append(slice_name, element1, element2, ...)` or
|
||||
`slice3 = append(slice1, slice2...)`
|
||||
|
||||
|
||||
For changing the length of array
|
||||
```go
|
||||
|
||||
func main() {
|
||||
arr1 := [6]int{9, 10, 11, 12, 13, 14} // An array
|
||||
myslice1 := arr1[1:5] // Slice array
|
||||
fmt.Printf("myslice1 = %v\n", myslice1)
|
||||
fmt.Printf("length = %d\n", len(myslice1))
|
||||
fmt.Printf("capacity = %d\n", cap(myslice1))
|
||||
|
||||
myslice1 = arr1[1:3] // Change length by re-slicing the array
|
||||
fmt.Printf("myslice1 = %v\n", myslice1)
|
||||
fmt.Printf("length = %d\n", len(myslice1))
|
||||
fmt.Printf("capacity = %d\n", cap(myslice1))
|
||||
|
||||
myslice1 = append(myslice1, 20, 21, 22, 23) // Change length by appending items
|
||||
fmt.Printf("myslice1 = %v\n", myslice1)
|
||||
fmt.Printf("length = %d\n", len(myslice1))
|
||||
fmt.Printf("capacity = %d\n", cap(myslice1))
|
||||
|
||||
|
||||
neededNumbers := arr3[:len(arr3)-4]
|
||||
numberCopy := make([]int, len(neededNumbers))
|
||||
copy(numberCopy, neededNumbers)
|
||||
|
||||
// or
|
||||
// neededNumbers... is like ...arr in js
|
||||
numberCopy = append([]int(nil), neededNumbers...)
|
||||
|
||||
|
||||
|
||||
fmt.Printf("numberCopy = %v\n", numberCopy)
|
||||
fmt.Printf("length = %d\n", len(numberCopy))
|
||||
fmt.Printf("capacity = %d\n", cap(numberCopy))
|
||||
fmt.Println("for neededNumbers:")
|
||||
fmt.Printf("capacity = %d\n", cap(neededNumbers))
|
||||
}
|
||||
```
|
||||
|
||||
Capacity will increase too automatically
|
||||
|
||||
|
||||
Memory Efficiency
|
||||
When copying elements from array, by default go will load all elements to memory so in order to copy few elements from large array it is better to use copy function.
|
||||
|
||||
|
||||
|
||||
**runes**
|
||||
character array of string but containing ascii code instead of characters
|
||||
```go
|
||||
import "unicode/utf8"
|
||||
|
||||
str:= "AB"
|
||||
runes:= []rune(str) // [65 66]
|
||||
|
||||
buf := make([]byte, utf8.RuneLen(runes[0]))
|
||||
utf8.EncodeRune(buf, runes[0]) // [65]
|
||||
|
||||
fmt.Println("string form: ", string(runes)) // AB
|
||||
|
||||
byteSlice := []byte(string(runes)) // [65 66]
|
||||
as character array
|
||||
fmt.Printf("%c\n", runes) // [A B]
|
||||
|
||||
|
||||
// to string slice
|
||||
sli := strings.Split(str, "") // [A B] -> not rune slice but string slice
|
||||
|
||||
slistr := strings.Join(sli, "") // AB
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
byteslice is of utf8 so takes mostly text but rune slice covers much as its int32
|
||||
36
joplin notion extension/Web Development/Go/Initial.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
Initial
|
||||
|
||||
Install go compiler.
|
||||
|
||||
Sample program
|
||||
```go
|
||||
|
||||
// file name : main.go
|
||||
package main
|
||||
import ("fmt")
|
||||
|
||||
func main() {
|
||||
fmt.Println("Hello World!")
|
||||
}
|
||||
```
|
||||
then run `go run main.go` or `go build -o main main.go && ./main`.
|
||||
for partilcular platform
|
||||
`GOOS=linux GOARCH=arm64 go build -o myapp-linux-arm64 . `
|
||||
and equivalent of `npm i`
|
||||
to install all packages
|
||||
`go get .` or `go mod tidy`
|
||||
to install specific package
|
||||
`go get github.com/spf13/cobra@latest`
|
||||
to remove go package
|
||||
simply remove import statements and then run `go mod tidy`
|
||||
|
||||
for initiating like `npm init -y`
|
||||
use `go mod init <module_name>`
|
||||
|
||||
|
||||
Program explanation
|
||||
1. in go every program is part of package that's why here is ths package main
|
||||
2. fmt package is imported
|
||||
3. main function
|
||||
4. fmt.Println is used to print text
|
||||
5. Comments are like in C ie `//` for single line and `/* */` for multi line
|
||||
4
joplin notion extension/Web Development/Go/Resources.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
Resources
|
||||
|
||||
https://github.com/mauricioabreu/golings
|
||||
https://go.dev/tour/basics/1
|
||||
75
joplin notion extension/Web Development/Go/databases.md
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
databases
|
||||
|
||||
sqlite
|
||||
https://www.sqlitetutorial.net/sqlite-go/connect/
|
||||
|
||||
connecting
|
||||
|
||||
```go
|
||||
|
||||
func NewDB() *sql.DB {
|
||||
// err := errors.New("some error")
|
||||
|
||||
db, err := sql.Open("sqlite", "./main.db")
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return nil
|
||||
}
|
||||
fmt.Println("Connected to the SQLite database successfully.")
|
||||
|
||||
|
||||
fmt.Println("Table countries was created successfully.")
|
||||
|
||||
return db
|
||||
}
|
||||
```
|
||||
|
||||
creating table
|
||||
```go
|
||||
func CreateTable(db *sql.DB) (sql.Result, error) {
|
||||
|
||||
sql := fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %v(
|
||||
id TEXT PRIMARY KEY,
|
||||
name TEXT NOT NULL,
|
||||
price REAL NOT NULL,
|
||||
file TEXT
|
||||
);`, TABLE_NAME)
|
||||
|
||||
return db.Exec(sql)
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
findall
|
||||
|
||||
```go
|
||||
func FindAll(db *sql.DB) ([]types.Book, error) {
|
||||
|
||||
sql := fmt.Sprintf(`select * from %v`, TABLE_NAME)
|
||||
|
||||
rows, err := db.Query(sql)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var books []types.Book
|
||||
for rows.Next() {
|
||||
b := &types.Book{}
|
||||
err := rows.Scan(&b.Id, &b.Name, &b.Price, &b.Filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
books = append(books, *b)
|
||||
}
|
||||
|
||||
fmt.Println("finall: ", books)
|
||||
|
||||
return books, nil
|
||||
}
|
||||
```
|
||||
|
||||
we cant just use sql.Rows directly as it is stream so using Next() we read it row by row
|
||||
3
joplin notion extension/Web Development/Go/discordgo.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
discordgo
|
||||
https://github.com/bwmarrin/discordgo
|
||||
[discordgo-master.zip](../../../_resources/discordgo-master.zip)
|
||||
50
joplin notion extension/Web Development/Go/extras.md
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
extras
|
||||
|
||||
- to get type of variable
|
||||
`fmt.Println(reflect.TypeOf(student))`
|
||||
|
||||
- for signals
|
||||
`signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)`
|
||||
- sc — a chan os.Signal (must be buffered, e.g. make(chan os.Signal, 1)) that will receive the signal values.
|
||||
- syscall.SIGINT — interrupt from the keyboard (Ctrl+C).
|
||||
- syscall.SIGTERM — polite termination request (e.g. kill <pid> or what Kubernetes sends on pod shutdown).
|
||||
- os.Interrupt — a platform-agnostic alias; on Unix it's the same as syscall.SIGINT, on Windows it also covers Ctrl+Break.
|
||||
|
||||
|
||||
for deeply mested objects printing in console
|
||||
|
||||
```go
|
||||
data, _ := json.MarshalIndent(m, "", " ")
|
||||
fmt.Printf("detected: %v\n", string(data))
|
||||
```
|
||||
|
||||
|
||||
|
||||
go equivalent to `fs.mkdirSync(dirPath,{recursive: true}`
|
||||
|
||||
this will create directories recurselovely and wont throw error if it exist
|
||||
```go
|
||||
err := os.MkdirAll(dirPath, 0755)
|
||||
```
|
||||
|
||||
creating a build for all platfoms
|
||||
|
||||
script
|
||||
```sh
|
||||
#!/bin/bash
|
||||
# Iterate through all supported GOOS/GOARCH combinations
|
||||
go tool dist list | while read platform; do
|
||||
# Split platform into OS and ARCH
|
||||
GOOS=${platform%/*}
|
||||
GOARCH=${platform#*/}
|
||||
|
||||
# Define output filename
|
||||
output_name="myapp-${GOOS}-${GOARCH}"
|
||||
if [ "$GOOS" = "windows" ]; then
|
||||
output_name+=".exe"
|
||||
fi
|
||||
|
||||
# Build the binary
|
||||
env GOOS=$GOOS GOARCH=$GOARCH go build -o "$output_name" .
|
||||
done
|
||||
```
|
||||
21
joplin notion extension/Web Development/Go/regex.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
regex
|
||||
https://gobyexample.com/regular-expressions
|
||||

|
||||
|
||||
for url
|
||||
```go
|
||||
func DoesContainURL(str string) (bool, error) {
|
||||
// regex := `/^https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&\/=]*)$/`
|
||||
regex := `https?://[^\s]+`
|
||||
|
||||
res, err := regexp.MatchString(regex, str)
|
||||
|
||||
fmt.Println("does: ", res)
|
||||
|
||||
return res, err
|
||||
}
|
||||
|
||||
DoesContainURL("sd http://yourrt.com/122 sads") // true
|
||||
|
||||
|
||||
```
|
||||
234
joplin notion extension/Web Development/Go/routing.md
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
routing
|
||||
|
||||
**from llm**
|
||||
|
||||
Sure! Let's create a simple REST API in Go (Golang) and I'll explain everything step by step. By the end of this, you'll have a basic understanding of how to create and run a Go REST API.
|
||||
|
||||
---
|
||||
|
||||
### What is a REST API?
|
||||
A REST API (Representational State Transfer Application Programming Interface) is a way for two systems to communicate over HTTP. It uses standard HTTP methods like `GET`, `POST`, `PUT`, and `DELETE` to perform operations on resources (like data).
|
||||
|
||||
---
|
||||
|
||||
### Step 1: Install Go
|
||||
Before we start, make sure you have Go installed on your machine. You can download it from the official website: [https://golang.org/dl/](https://golang.org/dl/).
|
||||
|
||||
To verify the installation, run:
|
||||
```bash
|
||||
go version
|
||||
```
|
||||
You should see the installed Go version.
|
||||
|
||||
---
|
||||
|
||||
### Step 2: Create a Go Project
|
||||
1. Create a new directory for your project:
|
||||
```bash
|
||||
mkdir go-rest-api
|
||||
cd go-rest-api
|
||||
```
|
||||
|
||||
2. Initialize a Go module:
|
||||
```bash
|
||||
go mod init go-rest-api
|
||||
```
|
||||
This creates a `go.mod` file, which manages dependencies.
|
||||
|
||||
---
|
||||
|
||||
### Step 3: Write the REST API Code
|
||||
Create a file named `main.go` in your project directory and add the following code:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// Item represents a simple data structure
|
||||
type Item struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// In-memory "database" to store items
|
||||
var items []Item
|
||||
|
||||
// Get all items
|
||||
func getItems(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(items)
|
||||
}
|
||||
|
||||
// Get a single item by ID
|
||||
func getItem(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
params := mux.Vars(r) // Get route parameters
|
||||
id, _ := strconv.Atoi(params["id"])
|
||||
|
||||
// Find the item with the matching ID
|
||||
for _, item := range items {
|
||||
if item.ID == id {
|
||||
json.NewEncoder(w).Encode(item)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// If not found, return a 404
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
|
||||
// Create a new item
|
||||
func createItem(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
var item Item
|
||||
_ = json.NewDecoder(r.Body).Decode(&item) // Decode the request body into the item
|
||||
|
||||
// Assign a new ID and add to the list
|
||||
item.ID = len(items) + 1
|
||||
items = append(items, item)
|
||||
|
||||
json.NewEncoder(w).Encode(item)
|
||||
}
|
||||
|
||||
// Update an existing item
|
||||
func updateItem(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
params := mux.Vars(r)
|
||||
id, _ := strconv.Atoi(params["id"])
|
||||
|
||||
// Find the item and update it
|
||||
for index, item := range items {
|
||||
if item.ID == id {
|
||||
var updatedItem Item
|
||||
_ = json.NewDecoder(r.Body).Decode(&updatedItem)
|
||||
updatedItem.ID = id
|
||||
items[index] = updatedItem
|
||||
json.NewEncoder(w).Encode(updatedItem)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// If not found, return a 404
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
|
||||
// Delete an item
|
||||
func deleteItem(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
params := mux.Vars(r)
|
||||
id, _ := strconv.Atoi(params["id"])
|
||||
|
||||
// Find the item and remove it
|
||||
for index, item := range items {
|
||||
if item.ID == id {
|
||||
items = append(items[:index], items[index+1:]...)
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// If not found, return a 404
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Initialize the router
|
||||
router := mux.NewRouter()
|
||||
|
||||
// Add some initial data
|
||||
items = append(items, Item{ID: 1, Name: "Item 1"})
|
||||
items = append(items, Item{ID: 2, Name: "Item 2"})
|
||||
|
||||
// Define routes
|
||||
router.HandleFunc("/items", getItems).Methods("GET")
|
||||
router.HandleFunc("/items/{id}", getItem).Methods("GET")
|
||||
router.HandleFunc("/items", createItem).Methods("POST")
|
||||
router.HandleFunc("/items/{id}", updateItem).Methods("PUT")
|
||||
router.HandleFunc("/items/{id}", deleteItem).Methods("DELETE")
|
||||
|
||||
// Start the server
|
||||
fmt.Println("Server is running on port 8080...")
|
||||
log.Fatal(http.ListenAndServe(":8080", router))
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 4: Install Dependencies
|
||||
The code uses the `gorilla/mux` package for routing. Install it by running:
|
||||
```bash
|
||||
go get -u github.com/gorilla/mux
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Step 5: Run the API
|
||||
To run the API, use the following command:
|
||||
```bash
|
||||
go run main.go
|
||||
```
|
||||
|
||||
The server will start on `http://localhost:8080`.
|
||||
|
||||
---
|
||||
|
||||
### Step 6: Test the API
|
||||
You can use tools like [Postman](https://www.postman.com/) or `curl` to test the API.
|
||||
|
||||
#### Endpoints:
|
||||
1. **GET** `/items` - Get all items.
|
||||
2. **GET** `/items/{id}` - Get a single item by ID.
|
||||
3. **POST** `/items` - Create a new item.
|
||||
4. **PUT** `/items/{id}` - Update an existing item.
|
||||
5. **DELETE** `/items/{id}` - Delete an item.
|
||||
|
||||
#### Example Requests:
|
||||
- **Get all items:**
|
||||
```bash
|
||||
curl http://localhost:8080/items
|
||||
```
|
||||
|
||||
- **Get a single item:**
|
||||
```bash
|
||||
curl http://localhost:8080/items/1
|
||||
```
|
||||
|
||||
- **Create a new item:**
|
||||
```bash
|
||||
curl -X POST -H "Content-Type: application/json" -d '{"name": "New Item"}' http://localhost:8080/items
|
||||
```
|
||||
|
||||
- **Update an item:**
|
||||
```bash
|
||||
curl -X PUT -H "Content-Type: application/json" -d '{"name": "Updated Item"}' http://localhost:8080/items/1
|
||||
```
|
||||
|
||||
- **Delete an item:**
|
||||
```bash
|
||||
curl -X DELETE http://localhost:8080/items/1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Explanation of the Code
|
||||
1. **`Item` Struct**: Represents a simple data structure with `ID` and `Name` fields.
|
||||
2. **`items` Slice**: Acts as an in-memory database to store items.
|
||||
3. **Routing**: The `gorilla/mux` package is used to define routes and handle HTTP methods.
|
||||
4. **Handlers**: Functions like `getItems`, `getItem`, `createItem`, `updateItem`, and `deleteItem` handle the logic for each endpoint.
|
||||
5. **JSON Encoding/Decoding**: The `encoding/json` package is used to convert Go structs to JSON and vice versa.
|
||||
|
||||
---
|
||||
|
||||
### Step 7: Learn More
|
||||
- Go Documentation: [https://golang.org/doc/](https://golang.org/doc/)
|
||||
- Gorilla Mux Documentation: [https://github.com/gorilla/mux](https://github.com/gorilla/mux)
|
||||
|
||||
Let me know if you have any questions! 😊
|
||||
176
joplin notion extension/Web Development/Go/snippets.md
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
snippets
|
||||
|
||||
js to go mappings
|
||||
[js-to-go.html](../../../_resources/js-to-go.html)
|
||||
[js-to-go_1.html](../../../_resources/js-to-go_1.html)
|
||||
|
||||

|
||||
|
||||
tracking time
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func myExpensiveFunction() {
|
||||
// 1. Tracks starting time and defers the calculation
|
||||
defer func(start time.Time) {
|
||||
fmt.Printf("Function took: %v\n", time.Since(start))
|
||||
}(time.Now())
|
||||
|
||||
// 2. Your actual function logic here
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
func main() {
|
||||
myExpensiveFunction()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
for printing tabular data
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Initialize tabwriter: output, minwidth, tabwidth, padding, padchar, flags
|
||||
w := tabwriter.NewWriter(os.Stdout, 1, 1, 3, ' ', 0)
|
||||
|
||||
// Print the header row (terminate columns with \t and rows with \n)
|
||||
fmt.Fprintln(w, "ID\tNAME\tROLE\tSTATUS\t")
|
||||
|
||||
// Print data rows
|
||||
fmt.Fprintln(w, "1\tAlice Vance\tDeveloper\tActive\t")
|
||||
fmt.Fprintln(w, "2\tBob Miller\tManager\tAway\t")
|
||||
fmt.Fprintln(w, "105\tCharlie\tDesigner\tOffline\t")
|
||||
|
||||
// Flush to format and output everything to the console
|
||||
w.Flush()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
for env file parsing
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Loads .env file into os.Environ()
|
||||
err := godotenv.Load()
|
||||
if err != nil {
|
||||
log.Fatal("Error loading .env file")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
or without external library
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func loadEnvFile(path string) error {
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
|
||||
// skip empty lines and comments
|
||||
if line == "" || strings.HasPrefix(line, "#") {
|
||||
continue
|
||||
}
|
||||
|
||||
// strip optional "export " prefix
|
||||
line = strings.TrimPrefix(line, "export ")
|
||||
|
||||
// for inline comments
|
||||
if strings.HasPrefix(line, `"`) || strings.HasPrefix(line, `'`) {
|
||||
// quoted — keep everything between the quotes
|
||||
line = strings.Trim(line, `"'`)
|
||||
} else {
|
||||
// unquoted — cut at first " #" (space + hash)
|
||||
if idx := strings.Index(line, " #"); idx != -1 {
|
||||
line = strings.TrimSpace(line[:idx])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
key, value, found := strings.Cut(line, "=")
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
|
||||
key = strings.TrimSpace(key)
|
||||
value = strings.TrimSpace(value)
|
||||
|
||||
// strip surrounding quotes
|
||||
value = strings.Trim(value, `"'`)
|
||||
|
||||
os.Setenv(key, value)
|
||||
}
|
||||
return scanner.Err()
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := loadEnvFile(".env"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println(os.Getenv("DB_HOST"))
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
for timestamps
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
unixTimestamp := int64(1615460256)
|
||||
t := time.Unix(unixTimestamp, 0)
|
||||
isoString := t.Format(time.RFC3339)
|
||||
// or for readibility
|
||||
// timeISOString := time.Time.Local(t).String()
|
||||
// or for gmt
|
||||
// timeISOString := time.Time.UTC(t).Format(http.TimeFormat)
|
||||
fmt.Println(isoString) // Output: 2021-03-11T06:17:36Z
|
||||
}
|
||||
```
|
||||
|
||||
for milli sec one
|
||||
|
||||
```go
|
||||
unixMillis := int64(1615460256000)
|
||||
t := time.Unix(unixMillis/1000, (unixMillis%1000)*int64(time.Millisecond))
|
||||
fmt.Println(t.Format(time.RFC3339))
|
||||
```
|
||||
|
||||
14
joplin notion extension/Web Development/HTML/Label.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
Label
|
||||
|
||||
- for property of label element is useful for pointing to input element using its id
|
||||
for eg:
|
||||
```html
|
||||
<input type="file" id="actual-btn"/>
|
||||
|
||||
<!--our custom file upload button-->
|
||||
<label for="actual-btn">Choose File</label>
|
||||
```
|
||||
|
||||
Now when the user clicks on **label** will ask for uploading file too just like we click on **input**
|
||||
|
||||
|
||||
56
joplin notion extension/Web Development/Java/Extras.md
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
Extras
|
||||
- Alternaive of String.format in java
|
||||
```java
|
||||
String sql = "SELECT ${columns} FROM Users WHERE Lastname=?"
|
||||
.replace("${columns}", "name");
|
||||
```
|
||||
- Maven
|
||||
Maven Build Lifecycle Phases
|
||||
|
||||
Maven follows a build lifecycle consisting of several phases. When you run mvn package, Maven executes all preceding phases in the lifecycle:
|
||||
```text
|
||||
validate: Checks if the project is correct and all necessary information is available.
|
||||
compile: Compiles the source code.
|
||||
test-compile: Compiles the test source code.
|
||||
test: Runs the tests using the compiled test code.
|
||||
package: Packages the compiled code and resources into a JAR, WAR, or other artifact formats.
|
||||
```
|
||||
If you run `mvn test`, Maven will perform only up to the test phase. It does not proceed to the package phase, so no artifact will be created.
|
||||
When creating any maven project directory structure should be like this
|
||||
```text
|
||||
my-project/
|
||||
├── pom.xml
|
||||
├── src/
|
||||
├── main/
|
||||
├── java/
|
||||
└── com/
|
||||
└── example/
|
||||
└── MyClass.java
|
||||
├── resources/
|
||||
└── config.properties
|
||||
├── test/
|
||||
├── java/
|
||||
└── com/
|
||||
└── example/
|
||||
└── MyClassTest.java
|
||||
├── resources/
|
||||
└── test-config.properties
|
||||
|
||||
```
|
||||
- Creating a jar file
|
||||
- First compile the java code to some directory say `bin`
|
||||
`javac -d bin main.java` (-d bin to create a directory)
|
||||
- `jar cf proj.jar -C bin .` (c for creative archve , f to specify name of jar file, -C bin . to change to bin directory from current one)
|
||||
- for creating executable jar manifest file needs to be created too so create a file with name `MANIFEST.MF` an type following
|
||||
```makefile
|
||||
Manifest-Version: 1.0
|
||||
Main-Class: HelloWorld
|
||||
```
|
||||
Then add it in jar with
|
||||
`jar cfm proj.jar MANIFEST.MF -C bin .`
|
||||
- `jar tf proj.jar` : to verify it
|
||||
- `java -jar proj.jar`
|
||||
|
||||
|
||||
handling JSON in java
|
||||
- https://www.geeksforgeeks.org/parse-json-java/
|
||||
|
|
@ -0,0 +1,239 @@
|
|||
Coding 1 (Autowire and Dependency Injection)
|
||||
|
||||
- Once starter project is ready its time to do some other stuff
|
||||
- Create POJO (Plain old java object)
|
||||
In `com/example/demo` where there is java file create another file containing classA `classA.java`
|
||||
```java
|
||||
package com.example.demo;
|
||||
|
||||
@Component
|
||||
public class ClassA {
|
||||
private int aid;
|
||||
private String aname;
|
||||
private String tech;
|
||||
|
||||
public int getAid() {
|
||||
return aid;
|
||||
}
|
||||
|
||||
public String getAname() {
|
||||
return aname;
|
||||
}
|
||||
|
||||
public String getTech() {
|
||||
return tech;
|
||||
}
|
||||
|
||||
public void setAid(int aid) {
|
||||
this.aid = aid;
|
||||
}
|
||||
|
||||
public void setAname(String aname) {
|
||||
this.aname = aname;
|
||||
}
|
||||
|
||||
public void setTech(String tech) {
|
||||
this.tech = tech;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
- Now linking POJO with demo without DI
|
||||
```java
|
||||
package com.example.demo;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
@SpringBootApplication
|
||||
public class DemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
ConfigurableApplicationContext context= SpringApplication.run(DemoApplication.class, args);
|
||||
|
||||
|
||||
|
||||
ClassA a = new ClassA();
|
||||
|
||||
a.show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
- Now linking POJO with DI.
|
||||
```java
|
||||
package com.example.demo;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
@SpringBootApplication
|
||||
public class DemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
ConfigurableApplicationContext context= SpringApplication.run(DemoApplication.class, args);
|
||||
|
||||
|
||||
ClassA a = context.getBean(ClassA.class);
|
||||
|
||||
|
||||
a.show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
- Theory : SpringApplication.run will create a spring container and it will contain objects also called spring bean. When spring bean are created we have 2 different scopes in spring core(base version without any web, jdbc,etc) ie Singleton and Prototype. Singleton is the default one. Whenever a container is created object of class with @Component annotation will be created too. if we want them to be created manually then use Prototype scope. Advantage of protoptype is that multiple objects can be created while in singleton same object is returned everytime.
|
||||
- Add the scope prototype like this
|
||||
in `ClassA.java`
|
||||
```java
|
||||
@Component
|
||||
@Scope(value="prototype")
|
||||
public class ClassA {
|
||||
private int aid;
|
||||
private String aname;
|
||||
private String tech;
|
||||
|
||||
public ClassA(){
|
||||
super();
|
||||
System.out.println("Class A object created");
|
||||
}
|
||||
|
||||
public int getAid() {
|
||||
return aid;
|
||||
}
|
||||
//....
|
||||
```
|
||||
In `DemoApplication.java`
|
||||
```java
|
||||
ClassA a = context.getBean(ClassA.class);
|
||||
a.show();
|
||||
ClassA a1 = context.getBean(ClassA.class);
|
||||
a1.show();
|
||||
```
|
||||
- Create another POJO named Laptop
|
||||
in `Laptop.java`
|
||||
```java
|
||||
package com.example.demo;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class Laptop {
|
||||
private int lid;
|
||||
private String brand;
|
||||
|
||||
public String getBrand() {
|
||||
return brand;
|
||||
}
|
||||
|
||||
public int getLid() {
|
||||
return lid;
|
||||
}
|
||||
|
||||
public void setBrand(String brand) {
|
||||
this.brand = brand;
|
||||
}
|
||||
|
||||
public void setLid(int lid) {
|
||||
this.lid = lid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
// TODO Auto-generated method stub
|
||||
// return super.toString();
|
||||
|
||||
return "Laptop[lid="+lid+", brand="+brand+ "]";
|
||||
}
|
||||
|
||||
public void compile(){
|
||||
System.out.println("Compiling");
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
In `ClassA.java`
|
||||
```java
|
||||
package com.example.demo;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
// @Scope(value="prototype")
|
||||
public class ClassA {
|
||||
private int aid;
|
||||
private String aname;
|
||||
private String tech;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("laptop")
|
||||
private Laptop laptop;
|
||||
|
||||
public ClassA(){
|
||||
super();
|
||||
System.out.println("Class A object created");
|
||||
}
|
||||
|
||||
public int getAid() {
|
||||
return aid;
|
||||
}
|
||||
|
||||
public String getAname() {
|
||||
return aname;
|
||||
}
|
||||
|
||||
public String getTech() {
|
||||
return tech;
|
||||
}
|
||||
|
||||
public void setAid(int aid) {
|
||||
this.aid = aid;
|
||||
}
|
||||
|
||||
public void setAname(String aname) {
|
||||
this.aname = aname;
|
||||
}
|
||||
|
||||
public void setTech(String tech) {
|
||||
this.tech = tech;
|
||||
}
|
||||
|
||||
public Laptop getLaptop() {
|
||||
return laptop;
|
||||
}
|
||||
|
||||
public void setLaptop(Laptop laptop) {
|
||||
this.laptop = laptop;
|
||||
}
|
||||
|
||||
public void show()
|
||||
{
|
||||
System.out.println("in show");
|
||||
laptop.compile();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
- As ClassA is using object of Laptop class means it is dependent on Laptop class so Autowired annotation is used to link with bean of object type `Laptop.class`. If we want to link with object name then we have to use Qualifier annotation and provide name in string form inside parenthesis. By default object name is class name with all the character as lower case and in this case it will be `laptop`. it doesnt depend on name of instance created at ClassA. In order to give custom object name
|
||||
In `Laptop.java`
|
||||
```java
|
||||
@Component("lap")
|
||||
public class Laptop {
|
||||
```
|
||||
and in `ClassA.java`
|
||||
```java
|
||||
@Autowired
|
||||
@Qualifier("lap")
|
||||
private Laptop lapto;
|
||||
```
|
||||
|
|
@ -0,0 +1,346 @@
|
|||
Coding 2 (Web app with Spring boot)
|
||||
|
||||
- Advantage of spring boot is embeded tomcat means we dont have to download tomcat externally so its easy to deploy it too.
|
||||
- Create `HomeController.java` in com.example.demo
|
||||
```java
|
||||
package com.example.demo;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Controller
|
||||
public class HomeController {
|
||||
|
||||
@RequestMapping("home")
|
||||
@ResponseBody
|
||||
public String home(){
|
||||
System.out.println("hi");
|
||||
return "hi";
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
ResponseBody annotation means some data is being returned instead of some file. above can be replaced by simply using RestController annotation instead of Controller and we dont need to include ResponseBody
|
||||
```java
|
||||
package com.example.demo;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class HomeController {
|
||||
|
||||
@RequestMapping("home")
|
||||
public String home(){
|
||||
System.out.println("hi");
|
||||
return "hi";
|
||||
}
|
||||
}
|
||||
|
||||
````
|
||||
- To return a file say html file or image file put them at `src/main/resources/static` folder and return filename
|
||||
```java
|
||||
package com.example.demo;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
@Controller
|
||||
public class HomeController {
|
||||
|
||||
@RequestMapping("home")
|
||||
public String home(){
|
||||
System.out.println("home");
|
||||
return "home.html";
|
||||
}
|
||||
|
||||
@RequestMapping("image")
|
||||
public String image(){
|
||||
System.out.println("image");
|
||||
return "image.png";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**Application properties files**
|
||||
- Spring boot has auto configure thing which does configuration for us but we can modify it too by editing the file `application.properties` at `src/main/resources`
|
||||
- In `static` folder if we want to group them in some other folder like pages then we have to do this
|
||||
in `application.properties`
|
||||
```
|
||||
spring.application.name=demo
|
||||
spring.mvc.view.prefix=/pages/
|
||||
```
|
||||
We can have include
|
||||
`spring.mvc.view.suffix=.jsp` too but this is for jsp only and not for simple html
|
||||
- above will make changes globally for all routes so instead of using prefix we can simply do this when returning file `return "pages/home.html";`
|
||||
|
||||
|
||||
## Accepting client data
|
||||
https://docs.spring.io/spring-framework/reference/web/webmvc/mvc-controller/ann-requestmapping.html
|
||||
|
||||
- for returning files : https://www.geeksforgeeks.org/returning-an-image-or-a-file-with-spring/
|
||||
- In the below code there are 3 different examples for handling/parsing query strings and returning json or string
|
||||
- handling request and response servlet way : using write method of res and getParameter of req
|
||||
- handling response and request spring way
|
||||
: using `ResponseEntity<T>` and `RequestEntity<T>`
|
||||
- handling query parameter spring way : using `RequestParam` annotation
|
||||
- catching custom parameters : enclosing variable in curly braces in RequestMapping annotation and capturing it with PathVariable annotation
|
||||
- returning back files : using Path and UrlResource classes
|
||||
```java
|
||||
package com.example.demo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.UrlResource;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.RequestEntity;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
|
||||
@Controller
|
||||
public class HomeController {
|
||||
|
||||
@RequestMapping("home")
|
||||
// @ResponseBody
|
||||
public void home(HttpServletRequest req, HttpServletResponse res) throws IOException{
|
||||
|
||||
// handling request and response servlet way
|
||||
|
||||
// localhost:8080/home?name=<name>
|
||||
String name = req.getParameter("name");
|
||||
|
||||
// String json = "{\"name\" : \"homepage\"}";
|
||||
String json = String.format("{\"name\" : \"%s\"}", name);
|
||||
|
||||
System.out.println("home "+name);
|
||||
|
||||
res.setContentType("application/json");
|
||||
|
||||
PrintWriter out= res.getWriter();
|
||||
out.write(json);
|
||||
out.flush();
|
||||
|
||||
|
||||
// return "pages/home.html";
|
||||
// return "{\"name\" : \"homepage\"}";
|
||||
}
|
||||
|
||||
@RequestMapping("image")
|
||||
public String image(){
|
||||
System.out.println("image");
|
||||
return "image.png";
|
||||
}
|
||||
|
||||
@RequestMapping("json-data")
|
||||
public ResponseEntity<String> getJSON( RequestEntity<String> req) throws IOException{
|
||||
// handling response and request spring way
|
||||
|
||||
URI url = req.getUrl();
|
||||
|
||||
|
||||
|
||||
|
||||
// to get query string params like name=<name>&id=<id>
|
||||
String queryString=url.getQuery();
|
||||
|
||||
|
||||
|
||||
// String json = "{\"name\" : \"homepage\"}";
|
||||
String json = String.format("{\"queryString\" : \"%s\"}", queryString);
|
||||
|
||||
System.out.println("home "+queryString);
|
||||
|
||||
return ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).body(json);
|
||||
|
||||
}
|
||||
|
||||
// handling query parameter spring way
|
||||
@RequestMapping("query-param")
|
||||
@ResponseBody
|
||||
public String getQueryParam( @RequestParam("name") String name, @RequestParam("id") String id){
|
||||
System.out.println("name: "+name);
|
||||
return "name="+name+" id="+id;
|
||||
}
|
||||
|
||||
@RequestMapping("{itemid}")
|
||||
@ResponseBody
|
||||
public String getItemID(@PathVariable String itemid){
|
||||
System.out.println("itemid="+itemid);
|
||||
return itemid;
|
||||
}
|
||||
|
||||
@RequestMapping("file")
|
||||
public ResponseEntity<Resource> getFile() throws IOException{
|
||||
Path path = Paths.get("src/main/resources/static/image.png");
|
||||
|
||||
// Loading resource
|
||||
Resource resource =(Resource) new UrlResource(path.toUri());
|
||||
|
||||
return ResponseEntity.ok().contentType(MediaType.IMAGE_PNG).body(resource);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Model and View
|
||||
- ModelAndView is Holder for both Model and View in the web MVC framework
|
||||
- For understanding thymeleaf refer to this
|
||||
https://www.baeldung.com/thymeleaf-in-spring-mvc
|
||||
https://www.baeldung.com/java-thymeleaf-expression-types
|
||||
- Make sure thymeleaf is installed first. Add this dependency under dependencies section in `pom.xml`
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
- in thymeleaf to be some special tag attributes like `th:text` (for simple text) , `th:utext` (for nested HTML )
|
||||
in `HomeController.java`
|
||||
```java
|
||||
@RequestMapping("model-view")
|
||||
public ModelAndView modelview(@RequestParam("name") String myname){
|
||||
ModelAndView mv = new ModelAndView();
|
||||
mv.addObject("name", myname);
|
||||
|
||||
// refers to thyme.html
|
||||
mv.setViewName("thyme");
|
||||
|
||||
return mv;
|
||||
}
|
||||
```
|
||||
in `src/main/resources/templates/thyme.html`
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
<style>
|
||||
.red{
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1 class="greeting" th:text="${name}"></h1>
|
||||
<span th:utext="'my <span class=\'red\'>name ' +${name}+ '</span> is ' + ${name}"></span>
|
||||
<h1 class="greeting" th:text="${name}"></h1>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
at `http://localhost:8080/model-view?name=ipsum`
|
||||

|
||||
|
||||
|
||||
### Model
|
||||
- Instead of using RequestParam annotation to get query parameters we can simply create a POJO and pass pojo object as parameter in controller method. When we map it to route and when that route sends data to it then it will recieve it as object so with appropriate class object in parameter it is possible to read those query parameters.
|
||||
in `Alien.java`
|
||||
```java
|
||||
package com.example.demo;
|
||||
|
||||
public class Alien {
|
||||
private int aid;
|
||||
private String aname;
|
||||
private String lang;
|
||||
|
||||
public int getAid() {
|
||||
return aid;
|
||||
}
|
||||
|
||||
public String getAname() {
|
||||
return aname;
|
||||
}
|
||||
|
||||
public String getLang() {
|
||||
return lang;
|
||||
}
|
||||
|
||||
public void setAid(int aid) {
|
||||
this.aid = aid;
|
||||
}
|
||||
|
||||
public void setAname(String aname) {
|
||||
this.aname = aname;
|
||||
}
|
||||
|
||||
public void setLang(String lang) {
|
||||
this.lang = lang;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In `HomeController.java`
|
||||
```java
|
||||
@RequestMapping("model")
|
||||
public ModelAndView model(Alien alien)
|
||||
{
|
||||
|
||||
ModelAndView mv = new ModelAndView();
|
||||
mv.addObject("obj", alien);
|
||||
|
||||
mv.setViewName("thyme");
|
||||
|
||||
return mv;
|
||||
}
|
||||
```
|
||||
or we can use Model class too
|
||||
```java
|
||||
@RequestMapping("model")
|
||||
public String model(Alien alien, Model model)
|
||||
{
|
||||
|
||||
model.addAttribute("obj", alien);
|
||||
|
||||
return "thyme";
|
||||
}
|
||||
```
|
||||
in `thyme.html`
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
<style>
|
||||
.red{
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1 class="greeting" th:text="${obj.aname}"></h1>
|
||||
<span th:utext="'my <span class=\'red\'>name ' +${obj.aid}+ '</span> is ' + ${obj.aname}"></span>
|
||||
<h1 class="greeting" th:text="'My lang is '+${obj.lang}"></h1>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
at `http://localhost:8080/model?aname=telusko&aid=101&lang=java`
|
||||

|
||||
|
||||
## Services
|
||||
- Instead of having all logic in controllers we can create separate service beans . @Component, @Service. these annotations all control beans but for readbility we prefer Service when actually creating service
|
||||
|
|
@ -0,0 +1,255 @@
|
|||
Coding 3 (Spring REST)
|
||||
- Before diving into this some terminology and concepts
|
||||
- JDBC (Java Database Connectivity) : It is an API that is inbuilt in java for connecting to database
|
||||
- JPA (Java Persistent API) : It is ORM (Object Relational Mapping) . Useful to directly work with java objects instead of SQL statements. It maps java objects properties to respective fields of table of relatioal database.
|
||||
- JDBCTemplate : Internally use JDBC and eliminate problem with JDBC and make code more clear and concise. Enables us to directly write SQL queries.This is related to Spring boot
|
||||
- MySQL Connector/J (JDBC driver) : It is a JDBC Type 4 driver, which means that it is pure Java implementation of the MySQL protocol and does not rely on the MySQL client . This is required to use mysql in spring boot
|
||||
There is MySQL Connector/Java too but it is provided by third party and isnt official one
|
||||
- references : https://spring.io/guides/gs/relational-data-access
|
||||
https://spring.io/guides/gs/accessing-data-mysql
|
||||
https://www.geeksforgeeks.org/how-to-execute-multiple-sql-commands-on-a-database-simultaneously-in-jdbc/ (normal jdbc not jdbctemplate)
|
||||
https://mkyong.com/spring/spring-jdbctemplate-batchupdate-example/ (for batchupdate)
|
||||
- Java concepts
|
||||
- Anonymous inner class : A class with no name for which single object is created. Useful to create a new object without needing to create a subclass with overloading/overriding methods. To explain this lets simplify it to its normal form step by step
|
||||
Eg:
|
||||
Anonymous inner class
|
||||
```java
|
||||
new BatchPreparedStatementSetter() {
|
||||
|
||||
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||
ps.setString(1, books.get(i).getName());
|
||||
ps.setBigDecimal(2, books.get(i).getPrice());
|
||||
}
|
||||
|
||||
public int getBatchSize() {
|
||||
return books.size();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
inner class
|
||||
```java
|
||||
BatchPreparedStatementSetter setter = new BatchPreparedStatementSetter() {
|
||||
@Override
|
||||
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||
// Implementation of setting values for the prepared statement
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBatchSize() {
|
||||
// Implementation of batch size
|
||||
}
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
a proper class
|
||||
```java
|
||||
|
||||
// here BatchPreparedStatmentSetter in interface not class thats why implements is used not extends
|
||||
public class BookBatchPreparedStatementSetter implements BatchPreparedStatementSetter {
|
||||
|
||||
private final List<Book> books;
|
||||
|
||||
public BookBatchPreparedStatementSetter(List<Book> books) {
|
||||
this.books = books;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||
ps.setString(1, books.get(i).getName());
|
||||
ps.setBigDecimal(2, books.get(i).getPrice());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBatchSize() {
|
||||
return books.size();
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
- In the following code few things like
|
||||
- Dependencies that are to be installed are `spring-web`, `jdbc-api` and `mysql-connector-j`.
|
||||
- A separate class is used for this which will act as a bean called `DataLoader`.
|
||||
- Object of `JdbcTemplate` class can be created with DI through Autowired annotation.
|
||||
- execute method is used to perform sql query. By default only single query is allowed. to allow multiple queries `spring.datasource.url` must contain query parameter as `allowMultiQueries=true`.
|
||||
- There are other methods like `update`, `query`, `queryForList`, `batchUpdate` which accept 2nd/3rd parameter after sql query(1st para) and they support placeholder ie `?` for sql queries.
|
||||
- update method is for operations like insert,update,etc. query is for select, queryForList will return the records without need for manually mapping them. batchupdate is used to insert/update multiple records at once. same can be done with update too as it accepts array too but multiple placeholders needed to be added too and code would not be readable.
|
||||
in `application.properties`
|
||||
```yml
|
||||
spring.application.name=demo
|
||||
spring.datasource.url=jdbc:mysql://localhost:3306/test?allowMultiQueries=true
|
||||
spring.datasource.username=root
|
||||
spring.datasource.password=<password>
|
||||
```
|
||||
|
||||
Add following under dependencies section
|
||||
in `pom.xml`
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-jdbc</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j -->
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<version>9.0.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
in `DataLoader.java`
|
||||
```java
|
||||
package com.example.demo;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
class Name{
|
||||
|
||||
public int id;
|
||||
public String name;
|
||||
|
||||
Name(int id,String name){
|
||||
this.id=id;
|
||||
this.name=name;
|
||||
}
|
||||
}
|
||||
|
||||
@Component
|
||||
public class DataLoader {
|
||||
|
||||
@Autowired
|
||||
JdbcTemplate jdbcTemplate;
|
||||
|
||||
public void execute() throws Exception{
|
||||
// jdbcTemplate.execute ("drop table if exists customers");
|
||||
// jdbcTemplate.execute("create table customers(" + "id serial, name varchar(255))");
|
||||
|
||||
jdbcTemplate.execute("drop table if exists customers; create table customers(id serial, name varchar(255));");
|
||||
|
||||
jdbcTemplate.execute( String.format("INSERT INTO customers values (%d, '%s')", 1, "hey2"));
|
||||
jdbcTemplate.update("INSERT INTO customers values (?, ?)", 3, "hey3");
|
||||
|
||||
Object[] args = new Object[] {2, "y"};
|
||||
jdbcTemplate.update("INSERT INTO customers values (?, ?)",args);
|
||||
|
||||
List<Name> names= new ArrayList<>();
|
||||
names.add(new Name(4,"hey4" ));
|
||||
names.add(new Name(5,"hey5" ));
|
||||
names.add(new Name(6,"hey6" ));
|
||||
names.add(new Name(7,"hey7" ));
|
||||
|
||||
jdbcTemplate.batchUpdate("INSERT INTO customers values (?, ?)", new BatchPreparedStatementSetter() {
|
||||
public void setValues(PreparedStatement ps, int i) throws SQLException{
|
||||
ps.setInt(1, names.get(i).id);
|
||||
ps.setString(2, names.get(i).name);
|
||||
}
|
||||
|
||||
public int getBatchSize(){
|
||||
return names.size();
|
||||
}
|
||||
});
|
||||
|
||||
Object[] args2= new Object[]{"2"};
|
||||
List<String> lis= jdbcTemplate.query("select name from customers where id=?", new RowMapper<String>() {
|
||||
@Override
|
||||
public String mapRow(ResultSet rs, int rowNum) throws SQLException{
|
||||
return rs.getString("name");
|
||||
}
|
||||
},args2);
|
||||
|
||||
List<Map<String,Object>> lis2= jdbcTemplate.query("select * from customers", new RowMapper<Map<String,Object>>(){
|
||||
@Override
|
||||
public Map<String,Object> mapRow(ResultSet rs, int rowNum) throws SQLException{
|
||||
|
||||
Map<String,Object> row = new HashMap<>();
|
||||
int coln=rs.getMetaData().getColumnCount();
|
||||
|
||||
for(int i=1;i<= coln;i++){
|
||||
String colname = rs.getMetaData().getColumnName(i);
|
||||
Object colvalue = rs.getObject(i);
|
||||
row.put(colname,colvalue);
|
||||
}
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
} );
|
||||
|
||||
List<Map<String,Object>> lis3 = jdbcTemplate.queryForList("select * from customers");
|
||||
|
||||
System.out.println("lis3: "+lis3.toString());
|
||||
|
||||
|
||||
|
||||
|
||||
for(int i=0; i< lis.size();i++){
|
||||
System.out.println(i+": "+lis.get(i));
|
||||
}
|
||||
|
||||
System.out.println("lis2: "+lis2.toString());
|
||||
|
||||
for( Map<String,Object> map : lis2 ){
|
||||
Set<String> keys = map.keySet();
|
||||
keys.forEach(key -> {
|
||||
System.out.println(key+": "+map.get(key));
|
||||
|
||||
});
|
||||
System.out.println();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
in `DemoApplication.java`
|
||||
```java
|
||||
package com.example.demo;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
@SpringBootApplication
|
||||
public class DemoApplication {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ConfigurableApplicationContext context =SpringApplication.run(DemoApplication.class, args);
|
||||
|
||||
DataLoader dl= context.getBean(DataLoader.class);
|
||||
dl.execute();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,473 @@
|
|||
Coding 4 (Spring REST telusko)
|
||||
- Creating a sample form which will send data to controller and controller will store it in database
|
||||
- Added a get method to return records when id is given as request so a new view is added too
|
||||
|
||||
Creating POJO class at `src/main/com/example/demo/model`
|
||||
```java
|
||||
package com.example.demo.model;
|
||||
|
||||
public class Alien {
|
||||
private int aid;
|
||||
private String aname;
|
||||
|
||||
public int getAid() {
|
||||
return aid;
|
||||
}
|
||||
|
||||
public void setAid(int aid) {
|
||||
this.aid = aid;
|
||||
}
|
||||
|
||||
public String getAname() {
|
||||
return aname;
|
||||
}
|
||||
|
||||
public void setAname(String aname) {
|
||||
this.aname = aname;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
// TODO Auto-generated method stub
|
||||
return String.format("Alien [aid=%d] [aname=%s]",aid,aname);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
Alien alien = (Alien) obj;
|
||||
|
||||
// for String or any non primitive type like Integer,Long,etc its necessary to check using equals method as by default
|
||||
// == will check equality of reference not their value
|
||||
if( alien.getAid()==this.aid && this.aname.equals(alien.getAname()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Creating a view `home.html` at `src/main/resources/templates`
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="addAlien">
|
||||
<input type="text" name="aid"><br>
|
||||
<input type="text" name="aname"><br>
|
||||
<input type="submit"><br>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
Creating a view `showAlien.html` at `src/main/resources/templates`
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<h3 th:text="${alien}"></h3>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
Creating a class to handle database operations named `TableLoader` at `src/main/com/example/demo/model`
|
||||
```java
|
||||
package com.example.demo.model;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
@Component
|
||||
public class TableLoader {
|
||||
|
||||
final String TableName="alien";
|
||||
|
||||
@Autowired
|
||||
JdbcTemplate jdbcTemplate;
|
||||
|
||||
public void createTable(){
|
||||
jdbcTemplate.execute(String.format("drop table if exists %s; create table alien (AID serial, ANAME text)",TableName));
|
||||
|
||||
}
|
||||
|
||||
public void fillInitialData(){
|
||||
jdbcTemplate.update("insert into alien (ANAME) values (?)", "navin");
|
||||
}
|
||||
|
||||
public void insertData(Alien alien){
|
||||
jdbcTemplate.update("insert into alien (ANAME) values (?)", alien.getAname());
|
||||
}
|
||||
|
||||
public Alien findById(int aid){
|
||||
|
||||
|
||||
|
||||
List<Alien> resList = jdbcTemplate.query("select * from alien where AID=?", new RowMapper<Alien>() {
|
||||
@Override
|
||||
public Alien mapRow(ResultSet rs, int rowNum) throws SQLException{
|
||||
|
||||
Alien alien= new Alien();
|
||||
alien.setAid(rs.getInt("AID"));
|
||||
alien.setAname(rs.getString("ANAME"));
|
||||
|
||||
return alien;
|
||||
}
|
||||
},aid);
|
||||
|
||||
return resList.get(0);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Creating controller `AlienController`
|
||||
```java
|
||||
package com.example.demo.controller;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import com.example.demo.model.Alien;
|
||||
import com.example.demo.model.TableLoader;
|
||||
|
||||
@Controller
|
||||
public class AlienController {
|
||||
|
||||
@Autowired
|
||||
TableLoader tl;
|
||||
|
||||
@RequestMapping("/")
|
||||
public String home(){
|
||||
return "home";
|
||||
}
|
||||
|
||||
@RequestMapping("/addAlien")
|
||||
public String addAlien(Alien alien){
|
||||
tl.insertData(alien);
|
||||
return "home";
|
||||
}
|
||||
|
||||
@RequestMapping("/getAlien")
|
||||
public ModelAndView getAlien(@RequestParam int aid){
|
||||
ModelAndView mv= new ModelAndView("showAlien");
|
||||
|
||||
Alien alien = tl.findById(aid);
|
||||
|
||||
System.out.println("Alien: "+alien.toString());
|
||||
|
||||
mv.addObject(alien);
|
||||
return mv;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Finally our spring boot app class
|
||||
```java
|
||||
package com.example.demo;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
import com.example.demo.model.TableLoader;
|
||||
|
||||
@SpringBootApplication
|
||||
public class DemoApplication {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
ConfigurableApplicationContext context =SpringApplication.run(DemoApplication.class, args);
|
||||
|
||||
TableLoader tl= context.getBean(TableLoader.class);
|
||||
tl.createTable();
|
||||
tl.fillInitialData();
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
- Optimizing findById method
|
||||
- Create a separate class called `AlienRowMapper` which implments RowMapper interface and override mapRow method to map it to Alien class object (ResultSet -> Alien )
|
||||
```java
|
||||
package com.example.demo.model;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
|
||||
public class AlienRowMapper implements RowMapper<Alien>{
|
||||
|
||||
@Override
|
||||
public Alien mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
|
||||
Alien alien = new Alien();
|
||||
alien.setAid(rs.getInt("AID"));
|
||||
alien.setAname(rs.getString("ANAME"));
|
||||
|
||||
return alien;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
Modify method
|
||||
```java
|
||||
public Alien findById(int aid){
|
||||
Alien alien = jdbcTemplate.queryForObject("select * from alien where AID=?", new AlienRowMapper(),aid);
|
||||
|
||||
return alien;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### GET methods
|
||||
- Make sure to use either GetMapping or include GET in method parameter of RequestMapping to prevent conflict between same path but of different method requests
|
||||
in `AlienController`
|
||||
```java
|
||||
// get methods
|
||||
@RequestMapping("/aliens")
|
||||
@ResponseBody
|
||||
public String getAliens(){
|
||||
return tl.findAll().toString();
|
||||
}
|
||||
|
||||
@RequestMapping(path="/alien/{aid}",method = RequestMethod.GET,produces = {"application/json"})
|
||||
@ResponseBody
|
||||
public String getAlienByParam(@PathVariable("aid") int aid){
|
||||
return tl.findById(aid).toString();
|
||||
}
|
||||
```
|
||||
|
||||
in `TableLoader`
|
||||
```java
|
||||
public List<Alien> findAll(){
|
||||
return jdbcTemplate.query("select * from alien",new AlienRowMapper());
|
||||
}
|
||||
```
|
||||
- optional class : https://www.javatpoint.com/java-8-optional
|
||||
- spring boot have jackson-core class to handle java objects by converting them to json when passed as response
|
||||
- in `AlienController`
|
||||
```java
|
||||
@RequestMapping("/getAlien")
|
||||
public ModelAndView getAlien(@RequestParam int aid){
|
||||
ModelAndView mv= new ModelAndView("showAlien");
|
||||
|
||||
Optional<Alien> alienOption = tl.findById(aid);
|
||||
|
||||
Alien alien=alienOption.get();
|
||||
|
||||
System.out.println("Alien: "+alien.toString());
|
||||
|
||||
mv.addObject(alien);
|
||||
return mv;
|
||||
}
|
||||
|
||||
// get methods
|
||||
@RequestMapping("/aliens")
|
||||
@ResponseBody
|
||||
public List<Alien> getAliens(){
|
||||
return tl.findAll();
|
||||
}
|
||||
|
||||
// with Optional container if there is no object to be returned is null then it will handle that too
|
||||
@RequestMapping("/alien/{aid}")
|
||||
@ResponseBody
|
||||
public Optional<Alien> getAlienByParam(@PathVariable("aid") int aid){
|
||||
return tl.findById(aid);
|
||||
}
|
||||
```
|
||||
in `TableLoader`
|
||||
```java
|
||||
|
||||
public Optional<Alien> findById(int aid){
|
||||
Alien alien = jdbcTemplate.queryForObject("select * from alien where AID=?", new AlienRowMapper(),aid);
|
||||
|
||||
return Optional.ofNullable(alien);
|
||||
}
|
||||
```
|
||||
|
||||
### Content Negotiation
|
||||
- To tell server or client what type of content needs to be sent or accepted
|
||||
- jackson-core handle json but not xml so if accept type for response is xml then another package ie jackson dataformat xml need to be installed too. so add following in `pom.xml`
|
||||
```xml
|
||||
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-xml -->
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-xml</artifactId>
|
||||
<version>2.17.2</version>
|
||||
</dependency>
|
||||
|
||||
```
|
||||
- at server side if we wanna give a response of particular content type so that it is restricted to that only(if client wants json and restriction at server is xml then it will fail).
|
||||
When passing muliple arguments inside anootation we need to mention argument field too like path,produces,etc
|
||||
- in `AlienController`
|
||||
```java
|
||||
// this is also possible
|
||||
// @RequestMapping(path="/aliens",produces = {"application/xml","application/json"})
|
||||
@RequestMapping(path="/aliens",produces = {"application/xml"})
|
||||
@ResponseBody
|
||||
public List<Alien> getAliens(){
|
||||
return tl.findAll();
|
||||
}
|
||||
```
|
||||
so now u will have this when u try json
|
||||

|
||||
|
||||
## POST Request
|
||||
- for accepting post requests change that to `RequestMethod.POST`
|
||||
in `AlienController`
|
||||
```java
|
||||
@RequestMapping(path="/alien",consumes = "multipart/form-data", produces = "application/json",method = RequestMethod.POST)
|
||||
@ResponseBody
|
||||
public Alien addAlienPOST(Alien alien){
|
||||
tl.insertData(alien);
|
||||
return alien;
|
||||
}
|
||||
```
|
||||
for `RequestMapping(path="path1", method=RequestMethod.POST)` there is a shorthand form ie `PostMapping("path1")`
|
||||
- `multipart/form-data` content is not raw body so whenever we send raw data like json/xml we need to use annotation RequestBody otherwise no value will be catched to instance of alien object
|
||||
in `AlienController`
|
||||
```java
|
||||
@PostMapping("/alien")
|
||||
@ResponseBody
|
||||
public Alien addAlienPOST(@RequestBody Alien alien){
|
||||
tl.insertData(alien);
|
||||
return alien;
|
||||
}
|
||||
```
|
||||
|
||||
### PUT and DELETE
|
||||
- in the following code apprach for put is to save and update means if there is no resource found to be updated then insert operation will take place and new id will be generated and returned
|
||||
- In order to get the new generated idm object of KeyHolder class needs to be used and pass in update method of jdbctemplate appropiately.
|
||||
- in update method, preparedstatement way (ie overloading) is to be used.
|
||||
- findById needs to be modified to use query instead of queryforobject in order to not deal with emptyresultSet exception
|
||||
|
||||
in `TableLoader`
|
||||
```java
|
||||
public Optional<Alien> findById(int aid){
|
||||
List<Alien> results = jdbcTemplate.query(
|
||||
"SELECT * FROM alien WHERE AID = ?",
|
||||
new AlienRowMapper(),
|
||||
aid
|
||||
);
|
||||
|
||||
return results.stream().findFirst();
|
||||
}
|
||||
|
||||
public void deleteById(int aid){
|
||||
jdbcTemplate.update("delete from alien where AID=?", aid);
|
||||
}
|
||||
|
||||
public Alien saveOrUpdateData(Alien alien,int aid){
|
||||
// System.out.println("starting of saveorupdate");
|
||||
Optional<Alien> a= this.findById(aid);
|
||||
// System.out.println("before if");
|
||||
if(!a.isPresent()){
|
||||
// System.out.println("starting of if");
|
||||
String insertSQL= "insert into alien (ANAME) values (?)" ;
|
||||
KeyHolder keyHolder= new GeneratedKeyHolder();
|
||||
|
||||
// System.out.println("Before inserting");
|
||||
// jdbcTemplate.update(insertSQL, alien.getAname(),keyHolder,"AID");
|
||||
jdbcTemplate.update(connection->{
|
||||
PreparedStatement ps=connection.prepareStatement(insertSQL, new String[] {"AID"});
|
||||
ps.setString(1,alien.getAname());
|
||||
return ps;
|
||||
},keyHolder);
|
||||
// System.out.println("after inserting");
|
||||
Number generatedID = keyHolder.getKey();
|
||||
System.out.println("after getting key: "+generatedID.intValue());
|
||||
return this.findById(generatedID.intValue()).get();
|
||||
|
||||
|
||||
|
||||
}
|
||||
else{
|
||||
jdbcTemplate.update("update alien set ANAME=? where AID=?", alien.getAname(),aid);
|
||||
return this.findById(aid).get();
|
||||
}
|
||||
}
|
||||
```
|
||||
in `AlienController`
|
||||
```java
|
||||
@DeleteMapping("/alien/{aid}")
|
||||
@ResponseBody
|
||||
public Alien deleteAlien(@PathVariable int aid){
|
||||
Alien a = tl.findById(aid).get();
|
||||
tl.deleteById(aid);
|
||||
return a;
|
||||
}
|
||||
|
||||
@PutMapping("/alien/{aid}")
|
||||
@ResponseBody
|
||||
public Alien updateAlien(@RequestBody Alien alien, @PathVariable("aid") int aid){
|
||||
Alien a=tl.saveOrUpdateData(alien,aid);
|
||||
return a;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Spring Data REST
|
||||
Note : it requires spring data jpa as it is built on top of that
|
||||
- A way to create REST without controller or spring-web dependency.
|
||||
- First we will need `rest repositories` dependency so add this in `pom.xml` and install
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-rest</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
- we need to use annotation `RepositoryRestResource`
|
||||
syntax is
|
||||
`@RepositoryRestResource(collectionResourceRel="<base_url>",path="<path>")`
|
||||
- this will map the paths with jpaRepository functions so need to make a separate rest controller.
|
||||
- collectionResourceRel paramater is responsible for generating self and other resource links in response body
|
||||
in `AlienRepo`
|
||||
```java
|
||||
```java
|
||||
package com.example.demo;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springgramework.data.rest.core.annotation.RepositoryRestResource;
|
||||
|
||||
@RepositoryRestResource(collectionResourceRel="aliens",path="aliens")
|
||||
public interface AlienRepo extends JpaRepository<Alien,Integer> {
|
||||
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
```
|
||||
|
|
@ -0,0 +1,221 @@
|
|||
Coding 5 (Sprint Boot Testing)
|
||||
https://www.youtube.com/watch?v=kbr5RaRDgQk&list=PLS1QulWo1RIZ5Vy1lyTlfjqtbut9BijN9
|
||||
|
||||
- We need mockito and junit runner to test our api and repository so add following in `pom.xml`
|
||||
```xml
|
||||
<!-- https://mvnrepository.com/artifact/org.junit.platform/junit-platform-runner -->
|
||||
<dependency>
|
||||
<groupId>org.junit.platform</groupId>
|
||||
<artifactId>junit-platform-runner</artifactId>
|
||||
<version>1.11.0-M2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
|
||||
<dependency>
|
||||
<groupId>org.mockito</groupId>
|
||||
<artifactId>mockito-core</artifactId>
|
||||
<version>5.12.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
```
|
||||
|
||||
- In the following code, some things to be mentioned
|
||||
- Mock annotation will mark field as mock and InjectMock will mark a field where injection has to be performed
|
||||
- Separate List of records ie objects of Alien class has been created which will be used as repo which is to be expcted later
|
||||
- `Before` annotation methods are being used to setup objects or initializing things before testing
|
||||
- when method of mockito will expect a result in this case list of records when findAll method is used of repo
|
||||
- mockmvc instance is used to mimic controller and its perform method will mimic requests like GET in this case and later it is checking json after checking length of list of records and checking a random ie third record name here
|
||||
|
||||
in `src/test/java/AlienController.java`
|
||||
```java
|
||||
package com.example.demo.controller;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
||||
import static org.hamcrest.Matchers.hasSize; // Import for hasSize
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
// import org.assertj.core.internal.Arrays;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import com.example.demo.model.Alien;
|
||||
import com.example.demo.model.TableLoader;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class AlienControllerTest {
|
||||
private MockMvc mockMvc;
|
||||
|
||||
ObjectMapper objMapper = new ObjectMapper();
|
||||
ObjectWriter objwriter= objMapper.writer();
|
||||
|
||||
@Mock
|
||||
private TableLoader tLoader;
|
||||
|
||||
@InjectMocks
|
||||
private AlienController aController;
|
||||
|
||||
Alien alien1 = new Alien(101, "name101");
|
||||
Alien alien2 = new Alien(102, "name102");
|
||||
Alien alien3 = new Alien(103, "name103");
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Before
|
||||
public void setUp(){
|
||||
// initializes object with mock and injectmocks annotation
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
// builds mockmvc instance for Controller annotation objects
|
||||
this.mockMvc=MockMvcBuilders.standaloneSetup(aController).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAliens() throws Exception{
|
||||
|
||||
|
||||
|
||||
List<Alien> aliens= new ArrayList<>(Arrays.asList(alien1,alien2,alien3));
|
||||
|
||||
Mockito.when(tLoader.findAll()).thenReturn(aliens);
|
||||
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/aliens").
|
||||
contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk())
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$", hasSize(3)) )
|
||||
.andExpect(jsonPath("$[2].aname",is("name103") ));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetAlienByParam() throws Exception {
|
||||
|
||||
Mockito.when(tLoader.findById(alien1.getAid())).thenReturn(Optional.ofNullable(alien1));
|
||||
|
||||
MockHttpServletRequestBuilder mockRequest = MockMvcRequestBuilders.get("/alien/101")
|
||||
.contentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
mockMvc.perform(mockRequest).andExpect(status().isOk())
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$", notNullValue()) )
|
||||
// ;
|
||||
.andExpect(jsonPath("$.aname",is("name101") ));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
### POST Request Testing
|
||||
```java
|
||||
@Test
|
||||
public void testAddAlien() throws Exception{
|
||||
Alien alien = new Alien(101,"hey1");
|
||||
|
||||
// as insertAlien method of tlLoader s void so no result is expected thats why no when method is used
|
||||
|
||||
// converting object 'alien' to json
|
||||
String alienJSON = objwriter.writeValueAsString(alien);
|
||||
|
||||
MockHttpServletRequestBuilder mockRequest = MockMvcRequestBuilders.post("/alien")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.content(alienJSON);
|
||||
|
||||
mockMvc.perform(mockRequest).andExpect(status().isOk())
|
||||
.andExpect( jsonPath("$", notNullValue()))
|
||||
.andExpect(jsonPath("$.aname", is("hey1")));
|
||||
```
|
||||
|
||||
|
||||
### PUT Request Testing
|
||||
- when method use equals method to check result so if equals method is not overriden in POJO(Alien class here) then implement it
|
||||
- With use of when we can initialize some data too for testing. so if we r checking findByID is returning the record then it means after it checks with mockmvc request , its mock version is implemented too. Without using when if we try to update then it will be treated as new record not updating old one
|
||||
```java
|
||||
@Test
|
||||
public void testUpdateAlien() throws Exception {
|
||||
|
||||
// to check if equals method is working properly or not
|
||||
Alien updatedAlien = new Alien(101,"heyo1");
|
||||
String alienJSONTemp = objMapper.writeValueAsString(updatedAlien);
|
||||
Alien updatedAlien2 = objMapper.readValue(alienJSONTemp, Alien.class);
|
||||
assertEquals(updatedAlien, updatedAlien2);
|
||||
|
||||
|
||||
Alien alien = new Alien(101, "heyo1");
|
||||
|
||||
Mockito.when(tLoader.findById(alien1.getAid())).thenReturn(Optional.of(alien1));
|
||||
Mockito.when(tLoader.saveOrUpdateData(Mockito.eq(alien), Mockito.eq(101))).thenReturn(alien);
|
||||
|
||||
String alienJSON = objwriter.writeValueAsString(alien);
|
||||
|
||||
MockHttpServletRequestBuilder mockRequest = MockMvcRequestBuilders.put("/aliens/101")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.content(alienJSON);
|
||||
|
||||
ResultActions ra =mockMvc.perform(mockRequest).andExpect(status().isOk())
|
||||
.andExpect( jsonPath("$", notNullValue()))
|
||||
.andExpect(jsonPath("$.aname", is("heyo1")));
|
||||
|
||||
|
||||
// printing response json
|
||||
String responseJSON = ra.andReturn().getResponse().getContentAsString();
|
||||
System.out.println("resjson: "+responseJSON);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Delete request test
|
||||
```java
|
||||
@Test
|
||||
public void testDeleteAlien() throws Exception {
|
||||
|
||||
|
||||
|
||||
Mockito.when(tLoader.findById(alien1.getAid())).thenReturn(Optional.of(alien1));
|
||||
// Mockito.when(tLoader.deleteById(alien1.getAid())).thenReturn(alien1);
|
||||
|
||||
MockHttpServletRequestBuilder mockRequest = MockMvcRequestBuilders.delete("/alien/101")
|
||||
.contentType(MediaType.APPLICATION_JSON);
|
||||
|
||||
ResultActions ra = mockMvc.perform(mockRequest).andExpect(status().isOk())
|
||||
.andExpect(MockMvcResultMatchers.jsonPath("$", notNullValue()) )
|
||||
// ;
|
||||
.andExpect(jsonPath("$.aname",is("name101") ));
|
||||
|
||||
// printing response json
|
||||
String responseJSON = ra.andReturn().getResponse().getContentAsString();
|
||||
System.out.println("resjson: "+responseJSON);
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
Extras telusko
|
||||
|
||||
- for configuring h2 database(in memory database)
|
||||
- make sure package is there in pom.xml
|
||||
- add following in `application.properties`
|
||||
```yml
|
||||
spring.h2.console.enabled=true
|
||||
spring.datasource.platform=h2
|
||||
spring.datasource.url=jdbc:h2:mem:telusko
|
||||
```
|
||||
here telusko is name of database
|
||||
- now start your application and go to `localhost:8080/h2~console` and u will get a login page. now click on test connection button
|
||||
- for configuring JPA
|
||||
- make sure respective dependency is there and at `application.properties` along with spring.datasource properties one more is mentioned for say mysql
|
||||
`spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQLDialect`
|
||||
- in POJO add annotation `Entity` above class defintion and in instance say `aid` add `@Id` annotation
|
||||
- now a table with fields of those POJO instance name will be created
|
||||
- u can add `data.sql` in `src/main/resources` to add initial data
|
||||
- in order to do crud operations use CrudRepository which is a part of spring data commons which is part of JPA
|
||||
- Create this interface
|
||||
```java
|
||||
package com.example.demo;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
public interface AlienRepo extends CrudRepository<Other,Integer> {
|
||||
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
and then in your main file/controller to save data use
|
||||
```java
|
||||
public class HomeController(){
|
||||
@Autowire
|
||||
Alienrepo repo;
|
||||
|
||||
@RequestMapping("/addAlien")
|
||||
public String addAlien(Alien alien){
|
||||
repo.save(alien);
|
||||
return "home";
|
||||
}
|
||||
|
||||
@RequestMapping("/getAlien")
|
||||
public ModelAndView getAlien(@RequestParam int aid){
|
||||
ModelAndView mv= new ModelAndView("showAlien");
|
||||
Alien alien=repo.findById(aid).orElse(new Alien());
|
||||
mv.addObject(alien);
|
||||
return mv;
|
||||
}
|
||||
}
|
||||
```
|
||||
- More query methods for interface Repo
|
||||
- In the following code, these other query methods are defined by just declaring then by following certain conventions like `findBy<PropertyName><Operation>` here property like Tech,Aid(first letter must be capital and other as small)
|
||||
- everything is not configured with conventions so for complex queries `Query` annotation have to be used. `?1` is used instead of `?` bcz there can be other placeholders too and its to index them.
|
||||
```java
|
||||
package com.example.demo;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
public interface AlienRepo extends CrudRepository<Other,Integer> {
|
||||
|
||||
List<Alien> findByTech(String tech);
|
||||
|
||||
List<Alien> findByAidGreaterThan(int aid);
|
||||
|
||||
// jpql instead of sql
|
||||
@Query("from Alien where tech=?1 order by aname")
|
||||
List<Alien> findByTechSorted(String tech);
|
||||
}
|
||||
```
|
||||
122
joplin notion extension/Web Development/Java/Spring/Extras.md
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
Extras
|
||||
- parsing json using jackson
|
||||
https://mkyong.com/java/jackson-how-to-parse-json/
|
||||
[How to parse JSON string with Jackson - Mkyong.com.pdf](../../../../_resources/How%20to%20parse%20JSON%20string%20with%20Jackson%20-%20Mkyong.com.pdf)
|
||||
[How to parse JSON string with Jackson - Mkyong.com (22_9_2024 8_29_12 am).html](../../../../_resources/How%20to%20parse%20JSON%20string%20with%20Jackson%20-%20Mkyong.com.html)
|
||||
|
||||
|
||||
|
||||
|
||||
```java
|
||||
|
||||
package com.example.demo;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.json.*;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
|
||||
@SpringBootApplication
|
||||
public class DemoApplication {
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception{
|
||||
SpringApplication.run(DemoApplication.class, args);
|
||||
ObjectMapper objectMapper= new ObjectMapper();
|
||||
JsonNode obj=objectMapper.readTree("[\"java is oops\", \"java is not oops\", \"java is annoying\"]");
|
||||
if(obj.isArray()){
|
||||
for(int i=0;i<obj.size();i++){
|
||||
System.out.println(obj.get(i).asText());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
```
|
||||
- for json array to `List<String>`
|
||||
```java
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
List<String> options= objmapper.readValue(q.getOptions(), objmapper.getTypeFactory().constructCollectionType(List.class, String.class));
|
||||
```
|
||||
- spring cors
|
||||
https://spring.io/guides/gs/rest-service-cors
|
||||
```java
|
||||
package com.example.restservicecors;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class GreetingController {
|
||||
|
||||
private static final String template = "Hello, %s!";
|
||||
|
||||
private final AtomicLong counter = new AtomicLong();
|
||||
@CrossOrigin(origins = "http://localhost:9000")
|
||||
@GetMapping("/greeting")
|
||||
public Greeting greeting(@RequestParam(required = false, defaultValue = "World") String name) {
|
||||
System.out.println("==== get greeting ====");
|
||||
return new Greeting(counter.incrementAndGet(), String.format(template, name));
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Array.map equivalent in java
|
||||
```java
|
||||
List<Integer> correctOptions = questionsResponses.stream().map(questionsResponse-> questionsResponse.getCorrectOptionNumber()).toList();
|
||||
```
|
||||
- converting biginteger into int
|
||||
`int questionID = ((BigInteger) questionResponseMap.get("questionID")).intValue();`
|
||||
- when using dependency
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
by default it adds authentication layer for accessing rest api, if that is not needed then it can be disabled by adding following bean
|
||||
```java
|
||||
package com.example.demo; // Adjust the package name as needed
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
public class SecurityConfig {
|
||||
|
||||
@Bean
|
||||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.authorizeRequests()
|
||||
.anyRequest().permitAll() // Allow all requests
|
||||
.and()
|
||||
.csrf().disable(); // Optionally disable CSRF protection
|
||||
|
||||
return http.build();
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
- configure PORT
|
||||
https://www.baeldung.com/spring-boot-change-port
|
||||
in application.properties
|
||||
`server.PORT=8081`
|
||||
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
Getting started
|
||||
|
||||
|
||||
**Dependency injection**
|
||||
https://www.youtube.com/watch?v=J1f5b4vcxCQ : Dependeny injection, the best pattern
|
||||
|
||||
Dependency
|
||||
- there r functions or objects that use other objects or functions and they r called dependency. There are 2 types of coupling.
|
||||
1. Hard coupling: Here dependency cant be changed
|
||||
2. Loose coupling: To change dependency in future
|
||||
|
||||
|
||||
Dependency injection
|
||||
- Instead of instantiating new code in constructor or function in same braces/scope we pass it instead through parameter to be used.
|
||||
- Main goal of dependency injection is to achieve loose coupling.
|
||||
eg
|
||||
without DI(Dependency Injection)
|
||||
```java
|
||||
public class Laptop{
|
||||
HardDrive obj1 = new HitachiHD();
|
||||
}
|
||||
```
|
||||
with DI
|
||||
```java
|
||||
public class Laptop{
|
||||
HardDrive obj1;
|
||||
Laptop(HardDrive obj){
|
||||
this.obj1= obj;
|
||||
}
|
||||
}
|
||||
```
|
||||
- It is possible using external service. That service is responsible for creating objects.
|
||||
- Example in spring boot
|
||||
```java
|
||||
class Laptop{
|
||||
@Autowired
|
||||
HardDrive obj1;
|
||||
}
|
||||
|
||||
@Component
|
||||
class HitachiHD implements HardDrive{
|
||||
// ...
|
||||
}
|
||||
```
|
||||
With this `@Autorired` annotation it will find the component which is tagged by `@Component` to connect to it.
|
||||
- Not only this is useful to prevent tight coupling, but also for testing.
|
||||
When we wanna test laptop
|
||||
then we may not need to check harddrive bcz it is already tested so with these we can separate it too. We can create *mock object* of the class if it is loosely coupled.
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
Initializing project
|
||||
https://docs.spring.io/spring-boot/tutorial/first-application/index.html
|
||||
|
||||
Download maven repos from https://mvnrepository.com/
|
||||
|
||||
1. First make sure that java and maven are installed. Gradle can be used too but maven is preferred for simplicity. check it by `java -version` and `mvn -v`.
|
||||
2. Like react have `package.json` which contains structure and what is to be installed so in spring boot it is `pom.xml`. pom stands for project object model. This is pom.xml for starter.
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>myproject</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.3.3</version>
|
||||
</parent>
|
||||
|
||||
<!-- Additional lines to be added here... -->
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
```
|
||||
3. Then in the root folder type `mvn package` in terminal to download related maven and spring plugins. its like `npm install` of react. This will download dependencies on `~/.m2/repository`
|
||||
4. Create `src/main/java/MyApplication.java` and type following
|
||||
```java
|
||||
// may recieve an error if not under custom package
|
||||
package com.myapp
|
||||
|
||||
// these will be added when starting app for first time
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
// controller as C in MVC
|
||||
@RestController
|
||||
@SpringBootApplication
|
||||
public class MyApplication {
|
||||
|
||||
// map to root directory
|
||||
@RequestMapping("/")
|
||||
String home() {
|
||||
return "Hello World!";
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
// running spring application
|
||||
SpringApplication.run(MyApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
5. Run `mvn spring-boot:run` in terminal to run app.
|
||||
6. Finally create an executeable jar to able to distribute it as it we need to package spring and maven plugins and packages into single jar file. All they need is java installed to run it . Add following after dependencies section in `pom.xml`
|
||||
```xml
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
```
|
||||
7. Then type `mvn package` to create the build (executable jar) in target folder.
|
||||
8. In order to run this jar file type `java -jar target/myproject-0.0.1-SNAPSHOT.jar`. In order to peek in this jar file use
|
||||
`jar tvf target/myproject-0.0.1-SNAPSHOT.jar`
|
||||
|
||||
|
||||
Alternatively u can go to https://start.spring.io/ and generate your starter project too
|
||||
here is one example with web dependency configured
|
||||
[spring web demo.zip](../../../../_resources/spring%20web%20demo.zip)
|
||||
|
||||
|
||||
|
||||
33
joplin notion extension/Web Development/Java/Spring/Intro.md
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
Intro
|
||||
|
||||
https://www.youtube.com/watch?v=QuvS_VLbGko : crash course of 1hr
|
||||
|
||||
https://www.baeldung.com/
|
||||
|
||||
https://www.youtube.com/watch?v=Ch163VfHtvA&list=PLsyeobzWxl7oA8QOlMtQsRT_I7Rx2hoX4 : telusko playlist
|
||||
|
||||

|
||||
|
||||
### EJB (Enterprise java bean)
|
||||
- Three types of EJB
|
||||
1. Session bean : Contains business logic that is invoked by local, remote or web service client
|
||||
2. Message driven bean : Contains business logic that is invoked by passing message
|
||||
3. Entity bean : Encapsulates state that can be persisted in database. it is deprecated and replaced by java persistent API
|
||||
|
||||
|
||||
POJO : Plain Old Java Object . Ordinary object which is not bound by special restriction. https://www.javatpoint.com/pojo-in-java
|
||||
|
||||
|
||||
Interface : multiple inheritance feature in java
|
||||
annotations : Java Annotation is a tag that represents the metadata i.e. attached with class, interface, methods or fields to indicate some additional information which can be used by java compiler and JVM.
|
||||
eg: `@Override`, `@Deprecated`
|
||||
|
||||
|
||||
**Spring**
|
||||
An open source framework to build enterprise java applications on any deployment platform. It is a collection of subfraneworks called layers such as Spring AOP. Spring Object-Relational Mapping (Spring ORM). Spring Web Flow, and Spring Web MVC.
|
||||
Spring can integrate with other frameworks like hibernate and struts.
|
||||
|
||||
**Spring boot**
|
||||
We need to work on configuration thouroughly instead of coding itself. Spring boot solves this issue as spring boot comes with built in configurations and dependencies so developers can focus on conventions. We can add additional configurations too on top of basic ones.
|
||||
Spring boot provides us with embedded server/tomcat so instead of needing a separate server, JVM is enough. So JAR file will have embedded tomcat.
|
||||
There is no XML file so we can add properties in `application.properties`
|
||||
15
joplin notion extension/Web Development/Java/Syntax.md
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
Syntax
|
||||
|
||||
- Template string in java
|
||||
```java
|
||||
String.format("INSERT INTO customers values (%d, '%s')", 2, "hey2")
|
||||
```
|
||||
|
||||
- for each loop in java
|
||||
```java
|
||||
String[] cars = {"Volvo", "BMW", "Ford", "Mazda"};
|
||||
for (String i : cars) {
|
||||
System.out.println(i);
|
||||
}
|
||||
|
||||
```
|
||||
4
joplin notion extension/Web Development/Java/Theory.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
Theory
|
||||
|
||||
JRE vs JVM vs JDK
|
||||
JRE identifies all the helpful class libraries needed for execution, while JVM is a subclass of JRE that decodes the bytecode into machine language and other minor tasks. JVM and JRE do not participate in development processes like debugging and compiling; JDK is used for them.
|
||||
215
joplin notion extension/Web Development/Java/Unit tests.md
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
Unit tests
|
||||
https://www.freecodecamp.org/news/java-unit-testing/
|
||||
https://www.youtube.com/watch?v=vZm0lHciFsQ : junit
|
||||
https://www.youtube.com/watch?v=HsQ9OwKA79s : mockito
|
||||
|
||||
- JUnit are for unit tests. Unit tests means isolating piece of code and then testing it to see if that component is working or not
|
||||
|
||||
- Initializing maven project
|
||||
Follow the maven project directory structure. Add following in `pom.xml`. In following code junit dependency is added with scope test(means they r recognized in src/test/java not src/main/java) and relevant source and target is set in cofiguration of maven compiler plugin. In configuration of maven jar plugin set the manifest to include class containing main method
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.example</groupId>
|
||||
<artifactId>demo</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>demo</name>
|
||||
<description>Demo project for JUnit Tests</description>
|
||||
<url/>
|
||||
<licenses>
|
||||
<license/>
|
||||
</licenses>
|
||||
<developers>
|
||||
<developer/>
|
||||
</developers>
|
||||
<scm>
|
||||
<connection/>
|
||||
<developerConnection/>
|
||||
<tag/>
|
||||
<url/>
|
||||
</scm>
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
<dependencies>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.10</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<source>11</source> <!-- Specify your desired Java version -->
|
||||
<target>11</target> <!-- Specify your desired Java version -->
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<configuration>
|
||||
|
||||
<archive>
|
||||
<manifestEntries>
|
||||
<Main-Class>com.example.demo.MyClass</Main-Class>
|
||||
</manifestEntries>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
</project>
|
||||
|
||||
```
|
||||
|
||||
- In following code , it can be noticed that test cases are in same package as in main program. The operation involve for test cases are methods like `assertEquals`, `assertTrue`,`assertNotEquals`, `assertThrows`, `assertDoesNotThrow`.
|
||||
- In GradleClassTest, in assertThrows lambda is used ie `()->` which contains the code to be executed and if throws exception matching the one in first param that the test case will pass
|
||||
|
||||
Program
|
||||
in `src/main/java/com/example/demo/SimpleCalculator.java`
|
||||
```java
|
||||
package com.example.demo;
|
||||
|
||||
public class SimpleCalculator {
|
||||
public int add(int numberA,int numberB){
|
||||
return numberA+numberB;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
Test case
|
||||
in `src/test/java/com/example/demo/SimpleCalculatorTest.java`
|
||||
```java
|
||||
package com.example.demo;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class SimpleCalculatorTest {
|
||||
@Test
|
||||
@DisplayName("2+2 equal to 4")
|
||||
void twoPlusTwoShouldEqualFour(){
|
||||
// var can be used for local variables so it can be used for SimpleCalculator here
|
||||
System.out.println("This test passed");
|
||||
var calculator=new SimpleCalculator();
|
||||
assertEquals(4,calculator.add(2, 2));
|
||||
assertTrue(calculator.add(2, 2)==4 );
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("3+7 equal to 10")
|
||||
void threePlusSevenShouldEqualTen(){
|
||||
var calculator=new SimpleCalculator();
|
||||
assertEquals(10, calculator.add(3, 7));
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
in `src/main/java/com/example/demo/GradleClass.java`
|
||||
```java
|
||||
package com.example.demo;
|
||||
|
||||
public class GraderClass {
|
||||
public char determineLetterGrade(int numberGrade){
|
||||
if(numberGrade<0){
|
||||
throw new IllegalArgumentException("Number grade cannot be negative");
|
||||
}
|
||||
|
||||
if(numberGrade <60){
|
||||
return 'F';
|
||||
}
|
||||
|
||||
if(numberGrade <70){
|
||||
return 'D';
|
||||
}
|
||||
|
||||
|
||||
if(numberGrade <80){
|
||||
return 'C';
|
||||
}
|
||||
|
||||
if(numberGrade <90){
|
||||
return 'B';
|
||||
}
|
||||
|
||||
return 'A';
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
in `src/test/java/com/example/demo/GradleClassTest.java`
|
||||
```java
|
||||
package com.example.demo;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class GraderClassTest {
|
||||
|
||||
GraderClass gc;
|
||||
@BeforeEach
|
||||
void setup(){
|
||||
gc= new GraderClass();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void NegativeReturnsIllegalArgumentException(){
|
||||
assertThrows(IllegalArgumentException.class, ()-> {gc.determineLetterGrade(-1);});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void FiftyMeansF(){
|
||||
assertEquals('F', gc.determineLetterGrade(50));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void SixtyMeansD(){
|
||||
assertEquals('D', gc.determineLetterGrade(60));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void SeventyMeansC(){
|
||||
assertEquals('C', gc.determineLetterGrade(70));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void EigtyMeansB(){
|
||||
assertEquals('B', gc.determineLetterGrade(80));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void NintyMeansA(){
|
||||
assertEquals('A', gc.determineLetterGrade(90));
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
29
joplin notion extension/Web Development/Java/jenv.md
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
jenv
|
||||
https://github.com/jenv/jenv
|
||||
https://www.youtube.com/watch?v=9FVZyeFDXo0
|
||||
|
||||
its a java version manager like nvm which alters the environment path
|
||||
|
||||
- Installation
|
||||
```bash
|
||||
git clone https://github.com/jenv/jenv.git ~/.jenv
|
||||
# Shell: bash
|
||||
echo 'export PATH="$HOME/.jenv/bin:$PATH"' >> ~/.bash_profile
|
||||
echo 'eval "$(jenv init -)"' >> ~/.bash_profile
|
||||
# Shell: zsh
|
||||
echo 'export PATH="$HOME/.jenv/bin:$PATH"' >> ~/.zshrc
|
||||
echo 'eval "$(jenv init -)"' >> ~/.zshrc
|
||||
```
|
||||
Here instead of `~/.bash_profile` it can be `~/.bashrc` too
|
||||
|
||||
- Configurations
|
||||
Check installed versons using `jenv versions` .
|
||||
To add java to jenv use
|
||||
`jenv add /usr/lib/jvm/java-11-openjdk`
|
||||
|
||||
- Using
|
||||
To set version locally for current directory
|
||||
`jenv local 11.0.2`
|
||||
For globally
|
||||
`jenv global 11.0.2`
|
||||
|
||||
121
joplin notion extension/Web Development/Javascript/Basics.md
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
Basics
|
||||
https://www.w3schools.com/js/js_htmldom_document.asp
|
||||
- DOM manipulation
|
||||
- To remove a node
|
||||
use `formElement.remove()`
|
||||
- To append at last
|
||||
`formElement.appendChild()`
|
||||
- `remove` only needs a reference to the child. `removeChild` needs a reference both to the parent and the child. The result is identical.
|
||||
document.body.removeChild(formElement). here body is upper section where formElement is lower one
|
||||
- replaceChild(new, old)
|
||||
- finding through collections : instead of finding though css selectors we can find through collections like body,head,forms,images,links. So to find form element through id use
|
||||
`const x = document.forms["frm1"];`
|
||||
here `frm1` is id
|
||||
- `insertBefore(newNode,referenceNode)` : insert new node before refernce node
|
||||
```js
|
||||
// Get a reference to the parent node
|
||||
const parentDiv = document.getElementById("childElement").parentNode;
|
||||
|
||||
// Begin test case [ 1 ] : Existing childElement (all works correctly)
|
||||
let sp2 = document.getElementById("childElement");
|
||||
parentDiv.insertBefore(newNode, sp2);
|
||||
```
|
||||
- `insertAfter(newnode,referenceNode)` : insert new node after refernce node
|
||||
we can create it by
|
||||
```js
|
||||
function insertAfter(newNode, existingNode) {
|
||||
existingNode.parentNode.insertBefore(newNode, existingNode.nextSibling);
|
||||
}
|
||||
```
|
||||
- Insert at first position
|
||||
`document.body.insertBefore(formElement,document.body.children[0])`
|
||||
- access child and parent element
|
||||
formElement.children => array of nodes
|
||||
formElement.parentElement => node
|
||||
- write vs appendChild
|
||||
https://stackoverflow.com/questions/22172589/document-write-vs-appendchild
|
||||
There is a difference between sequence. appendChild will execute on last but write during the stream
|
||||
eg:
|
||||
index1.html
|
||||
```html
|
||||
<script>
|
||||
console.log('1');
|
||||
var script = document.createElement('script');
|
||||
script.src = 'someScript.js';
|
||||
document.write(script.outerHTML);
|
||||
</script>
|
||||
<script>
|
||||
console.log('3');
|
||||
</script>
|
||||
```
|
||||
|
||||
index2.html
|
||||
```html
|
||||
<script>
|
||||
console.log('1');
|
||||
var script = document.createElement('script');
|
||||
script.src = 'someScript.js';
|
||||
document.body.appendChild(script);
|
||||
</script>
|
||||
<script>
|
||||
console.log('3');
|
||||
</script>
|
||||
```
|
||||
Output in 1st case will be `1,2,3` and in second case will be `1,3,2`.
|
||||
|
||||
- html
|
||||
innerHTML, innerText, textContent,outerHTML
|
||||
unlike innerHTML, outerHTML also include the outer structure too
|
||||
eg
|
||||
```js
|
||||
const div = document.createElement('div')
|
||||
div.innerHTML= `<p> Hello </p>`
|
||||
console.log(div.outerHTML) // outputs div and its innerHTML both
|
||||
```
|
||||
|
||||
|
||||
js maps
|
||||
```js
|
||||
const map = new Map();
|
||||
|
||||
map.set("a", 1);
|
||||
map.set("b", 2);
|
||||
map.set("c", 3);
|
||||
|
||||
console.log(map.get("a"));
|
||||
// Expected output: 1
|
||||
|
||||
map.set("a", 97);
|
||||
|
||||
console.log(map.get("a"));
|
||||
// Expected output: 97
|
||||
|
||||
console.log(map.size);
|
||||
// Expected output: 3
|
||||
|
||||
map.delete("b");
|
||||
|
||||
console.log(map.size);
|
||||
// Expected output: 2
|
||||
```
|
||||
|
||||
forEach is also supported in maps in latest version of js, in old versions they may not be supported so use
|
||||
`[...mapVariable].forEach` instead of `mapVariable.forEach`
|
||||
|
||||
|
||||
|
||||
collect all arrays from something and also being unique
|
||||
```js
|
||||
|
||||
|
||||
const VIDEOS = [
|
||||
{
|
||||
folder: "Nature Docs",
|
||||
title: "Coral Reef at Dawn",
|
||||
tags: ["ocean", "wildlife", "4k"],
|
||||
url: "https://storage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",
|
||||
},
|
||||
]
|
||||
|
||||
const allTags = [...new Set(VIDEOS.flatMap((v) => v.tags))].sort();
|
||||
```
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
Basics
|
||||
|
||||
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Your_first_WebExtension
|
||||
|
||||
- For extension named borderify , directory order should be like this:
|
||||
```
|
||||
borderify/
|
||||
-- icons/
|
||||
---- border-48.png
|
||||
--borderify.js
|
||||
--manifest.json
|
||||
```
|
||||
- contents of manifest.json
|
||||
` "matches": ["*://*.mozilla.org/*"],` this means that extension will work for the domain **mozilla.org**
|
||||
```json
|
||||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Borderify",
|
||||
"version": "1.0",
|
||||
|
||||
"description": "Adds a red border to all webpages matching mozilla.org.",
|
||||
|
||||
"icons": {
|
||||
"48": "icons/border-48.png"
|
||||
},
|
||||
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["*://*.mozilla.org/*"],
|
||||
"js": ["borderify.js"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- Contents of borderify.js
|
||||
`document.body.style.border = "5px solid red";`
|
||||
|
||||
- Go to `about:debugging` in firefox url tab and click on load temporary extension and go to borderify folder and click on manifest.json as it links to every thing. now this extension is added until browser restart
|
||||
|
||||
|
||||
- ### More (popups and content script)*
|
||||
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Your_second_WebExtension
|
||||

|
||||
|
||||
Structure
|
||||
```text
|
||||
beastify/
|
||||
|
||||
beasts/
|
||||
frog.jpg
|
||||
snake.jpg
|
||||
turtle.jpg
|
||||
|
||||
content_scripts/
|
||||
beastify.js
|
||||
|
||||
icons/
|
||||
beasts-32.png
|
||||
beasts-48.png
|
||||
|
||||
popup/
|
||||
choose_beast.css
|
||||
choose_beast.html
|
||||
choose_beast.js
|
||||
|
||||
manifest.json
|
||||
|
||||
```
|
||||
browser methods
|
||||
This browser object is a main difference between web apps and firefox add on as it let popup access paths and ability to communicate with content scripts.
|
||||
https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API
|
||||
Some are
|
||||
`browser.`
|
||||
- `runttime.` : This module provides information about your extension and the environment it's running in.
|
||||
- `getURL` : get url for the path. this path is used to access resources of the extension whole folder
|
||||
eg: `browser.runtime.getURL("beasts/frog.jpg")`
|
||||
- `onMessage`: Use this event to listen for messages from another part of your extension.
|
||||
eg
|
||||
```js
|
||||
browser.runtime.onMessage.addListener((message)=>{
|
||||
if(message.command==="beastify") {
|
||||
insertBeast(message.beastURL);
|
||||
}
|
||||
else if( message.command === "reset" ){
|
||||
removeExistingBeasts();
|
||||
}
|
||||
})
|
||||
```
|
||||
- `tabs.`
|
||||
- `insertCSS` : to inject css to active tab. this is an asynchronous function that returns promise
|
||||
eg :
|
||||
```js
|
||||
const hidePage=`body > :not(.beastify-image){
|
||||
display : none;
|
||||
}`;
|
||||
|
||||
await browser.tabs.insertCSS({code: hidePage})
|
||||
|
||||
```
|
||||
- `sendMessage` : to send single message from extension background script(or popup_script or page_script) to content scripts. its an asynchronous function
|
||||
eg :
|
||||
```js
|
||||
browser.tabs.sendMessage(tabs[0].id, {
|
||||
command : "beastify",
|
||||
beastURL : url
|
||||
})
|
||||
```
|
||||
- `removeCSS` : to remove css from the page which was injected by insertCSS method. it wont remove original CSS of page
|
||||
eg : `await browser.tabs.removeCSS({code: hidePage})`
|
||||
- `query` : Gets all tabs that have the specified properties, or all tabs if no properties are specified. an asynchronous function that returns `Promise<array>`
|
||||
eg : `const tabs=await browser.tabs.query({active: true, currentWindow : true})`
|
||||
- `executeScript` : injects javascript code to page. It is available for manifest v2 only
|
||||
eg : `browser.tabs.executeScript({file: "/content_scripts/beastify.js"})`
|
||||
or
|
||||
`browser.tabs.executeScript({code: "console.log('hello')"`
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
Chrome
|
||||
|
||||
- Simple one
|
||||
https://www.freecodecamp.org/news/building-chrome-extension/
|
||||
Manifest.json
|
||||
```json
|
||||
{
|
||||
"name": "Covid-19 Stats UK",
|
||||
"version": "1.0.0",
|
||||
"description": "latest covid data of UK",
|
||||
"manifest_version": 3,
|
||||
"author": "Sampurna Chapagain",
|
||||
"action":{
|
||||
"default_popup": "index.html",
|
||||
"default_title": "Latest Covid Report"
|
||||
}
|
||||
}
|
||||
```
|
||||
- Access active page dom
|
||||
https://infoheap.com/chrome-extension-tutorial-access-dom/
|
||||
https://www.sung.codes/blog/2019/getting-dom-content-from-chrome-extension-2
|
||||
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Debugging
|
||||
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
Signing
|
||||
|
||||
- After uploading it and getting approved by firefox add on store we get uuid. so now if we wanna distribute it wothout firefox add on store as it may get unlisted so only way is using xpi or zip format
|
||||
Before packing it add uuid in **manifest.json** like this:
|
||||
browser_specific_settings > gecko > id
|
||||
i believe that's the structure
|
||||
|
||||
```json
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
"id": "{id-in-curlys}",
|
||||
"strict_min_version": ""
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
firefox structure btw
|
||||
chromium bit different if you had planned to develop for that
|
||||
i think for chromium it's chrome_settings
|
||||
chrome_settings_overrides
|
||||
no not that
|
||||
it seems i'm mistaken
|
||||
both use same
|
||||
oh wait i'm not mistaken
|
||||
idk what chromium uses tho
|
||||
turns out you can also combine manifest for an extension
|
||||
use gecko for desktop
|
||||
and gecko_android for android
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
Tips
|
||||
|
||||
- Bypass caching
|
||||
When injecting link element for css file, the problem of caching can be annoying so append something in the url like this
|
||||
```js
|
||||
// Create a link element for the CSS file
|
||||
const linkElement = document.createElement('link');
|
||||
linkElement.rel = 'stylesheet';
|
||||
linkElement.href = browser.runtime.getURL('styles.css') + '?v=' + Date.now(); // Append a timestamp
|
||||
document.head.appendChild(linkElement);
|
||||
|
||||
```
|
||||
- Reset injected element
|
||||
When we inject DOM element and reload extension previous one wont get removed unless page is reloaded so tag all those inserted element with extension name or by adding it in class.
|
||||
`contentScript.js`
|
||||
```js
|
||||
|
||||
// removing elements of class of ext_name
|
||||
function reset1(){
|
||||
|
||||
const elements=document.querySelectorAll(`.${ext_name}`)
|
||||
|
||||
for(let ele of elements){
|
||||
ele.remove()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
reset1();
|
||||
|
||||
const navibar= document.createElement("div")
|
||||
navibar.className=`${ext_name} navigation_bar`
|
||||
navibar.innerHTML=`
|
||||
<button class=" nav_btn"> All Replies </button>
|
||||
`
|
||||
|
||||
|
||||
console.log('navibar: ',navibar.outerHTML);
|
||||
|
||||
|
||||
|
||||
const app=document.querySelector("body")
|
||||
app.insertBefore(navibar, app.children[0])
|
||||
|
||||
```
|
||||
|
||||
|
||||
in firefox to allow custom extensions for permanent without uploading in firefox
|
||||
|
||||
Type `about:config` in the address bar and press Enter
|
||||
Search for `xpinstall.signatures.required`.
|
||||
Ensure the value is set to false (toggle it by double-clicking if necessary).
|
||||
191
joplin notion extension/Web Development/Javascript/Extras.md
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
Extras
|
||||
|
||||
- event delegation
|
||||
to detect events in child elements without need to attach listener to each of them
|
||||
```js
|
||||
// Assuming ulElement is a reference to your <ul> element
|
||||
const ulElement = document.querySelector('ul');
|
||||
|
||||
// Add a click event listener to the ul element
|
||||
ulElement.addEventListener('click', function(event) {
|
||||
// Check if the clicked element is an li element
|
||||
if (event.target.tagName === 'LI') {
|
||||
// Get the text content of the clicked li element
|
||||
const clickedText = event.target.textContent;
|
||||
|
||||
// Do something with the clicked text
|
||||
console.log('Clicked li:', clickedText);
|
||||
}
|
||||
});
|
||||
|
||||
```
|
||||
- generate random string
|
||||
```js
|
||||
function generateRandomString(length) {
|
||||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
let result = '';
|
||||
const charactersLength = characters.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Example usage:
|
||||
const randomString = generateRandomString(10); // Generates a random string of length 10
|
||||
console.log(randomString);
|
||||
|
||||
```
|
||||
- form data directly through form element
|
||||
Note : make sure that input element contains name attribute as its value is the key/field of formdata
|
||||
just use
|
||||
```js
|
||||
<form action="/route/api" method="POST">
|
||||
<input type="text" name="city">
|
||||
</form>
|
||||
|
||||
const onSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const formData = new FormData(e.currentTarget);
|
||||
|
||||
// Convert FormData to a plain object for logging
|
||||
const formDataObj = {};
|
||||
formData.forEach((value, key) => {
|
||||
formDataObj[key] = value;
|
||||
});
|
||||
|
||||
console.log(formDataObj); // This will log a plain object with form data
|
||||
|
||||
const response = await fetch("/addschool/api", {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
});
|
||||
};
|
||||
|
||||
```
|
||||
this will just Formdata which is not multipart but of urlencoded and field will be `city`
|
||||
|
||||
for multipart form data
|
||||
|
||||
```html
|
||||
<form onSubmit={onSubmit}>
|
||||
<input type="text" name="city">
|
||||
</form>
|
||||
```
|
||||
- extract query params from url
|
||||
```js
|
||||
let searchParams = new URLSearchParams(window.location.search);
|
||||
const value = searchParams.get('field_name');
|
||||
|
||||
```
|
||||
- form validation methods
|
||||
https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#the-constraint-validation-api
|
||||
- to launch custom events use this
|
||||
```js
|
||||
const invalidEvent = new Event("invalid", {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
});
|
||||
|
||||
console.log("invalid event");
|
||||
e.target.dispatchEvent(invalidEvent);
|
||||
```
|
||||
|
||||
|
||||
|
||||
- Creating most apis easily
|
||||
To create mock api easily use something like json-server(simple way with less features) or hoverfly(complex way with more features)
|
||||
https://github.com/typicode/json-server
|
||||
https://github.com/SpectoLabs/hoverfly
|
||||
|
||||
|
||||
regex tip
|
||||
- When using parentheis for grouping in js, sometimes we just want to group and not to capture when usng exec method in js so use
|
||||
`/^(?:http|ftp):\/\/(.+)/` instead of `/^(http|ftp):\/\/(.+)/` .
|
||||
this `?:` signals exec to not capture
|
||||
|
||||
|
||||
conditionally set properties
|
||||
```js
|
||||
const isAdmin = true;
|
||||
|
||||
const user = {
|
||||
id: 1,
|
||||
name: "Alice",
|
||||
...(isAdmin && { role: "admin" }) // Spreads { role: "admin" } only if isAdmin is true
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
to convert intput element itno number easily use this
|
||||
```js
|
||||
const inputElement = document.getElementById("myInput");
|
||||
|
||||
// Returns a native JavaScript number directly (or NaN if empty/invalid)
|
||||
const num = inputElement.valueAsNumber;
|
||||
// const number = parseInt(inputElement.value)
|
||||
```
|
||||
|
||||
|
||||
|
||||
abort async tasks in between
|
||||
```js
|
||||
const processController = new AbortController();
|
||||
|
||||
async function performHeavyTask(signal) {
|
||||
try {
|
||||
console.log("Step 1 started...");
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
// Check if the event fired while Step 1 was running
|
||||
signal.throwIfAborted();
|
||||
|
||||
console.log("Step 2 started...");
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
// Check again before proceeding
|
||||
signal.throwIfAborted();
|
||||
|
||||
console.log("Task completed perfectly!");
|
||||
} catch (error) {
|
||||
if (error.name === 'AbortError') {
|
||||
console.log("Custom async workflow was stopped safely.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Triggering the stop on a custom event
|
||||
window.addEventListener('userLeftPage', () => {
|
||||
processController.abort();
|
||||
});
|
||||
|
||||
performHeavyTask(processController.signal);
|
||||
|
||||
```
|
||||
|
||||
for video hover and all this
|
||||
```js
|
||||
|
||||
let processController = null;
|
||||
|
||||
videoEle.addEventListener("mouseenter", () => {
|
||||
processController = new AbortController();
|
||||
|
||||
rotateThumbnails(processController.signal);
|
||||
});
|
||||
videoEle.addEventListener("mouseleave", () => {
|
||||
processController.abort();
|
||||
});
|
||||
```
|
||||
|
||||
to get content-type of response use
|
||||
|
||||
```js
|
||||
const response = await fetch('https://example.com');
|
||||
|
||||
// Get the raw content-type string (e.g., "application/json; charset=utf-8")
|
||||
const contentType = response.headers.get('content-type');
|
||||
console.log(contentType);
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
File handling
|
||||
|
||||
- Client(browser)
|
||||
|
||||
```jsx
|
||||
const encryptedFileInput = document.getElementById("encryptedFileInput");
|
||||
const encryptedFile = encryptedFileInput.files[0];
|
||||
|
||||
// Read the encrypted file
|
||||
const encryptedData = await encryptedFile.arrayBuffer();
|
||||
```
|
||||
- arrayBuffer vs blob
|
||||
blob is immutable and is the data type when we submit the file in form in client(browser)
|
||||
arraybuffer is the binary representation of file as thats how `fs.readFileSync` returns it
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Frameworks
|
||||
https://www.youtube.com/watch?v=WJRf7dh5Zws
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
Resources
|
||||
|
||||
- https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/README.md : book
|
||||
- https://www.udemy.com/course/the-complete-javascript-course/ : https://pixeldrain.com/l/wtrfxMof
|
||||
[The Complete JavaScript Course 2023 From Zero to Expert!.torrent](../../../_resources/The%20Complete%20JavaScript%20Course%202023%20From%20Zero%20to%20E.torrent)
|
||||
|
||||
- compare all js framwork
|
||||
https://component-party.dev/
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
Snippet links
|
||||
|
||||
- https://www.codingthai.com/tic-tac-toe-game-using-javascript/
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
Setup
|
||||
|
||||
- `npm create tauri-app@latest` and then fill prompts to configure your project
|
||||
Then use `npm i`
|
||||
- to run project in dev mode use `npm run tauri dev`
|
||||
- to build use `npm run tauri build` . if facing problem in build then use `NO_STRIP=true npm run tauri build`
|
||||
|
|
@ -0,0 +1,291 @@
|
|||
Basics
|
||||
|
||||
- By default if we inittialize variable we dont need to define type there as it will be automatically type inferenced.
|
||||
```ts
|
||||
let age = 30;
|
||||
```
|
||||
- Or we can use type annotations too
|
||||
```ts
|
||||
let age : number = 30;
|
||||
```
|
||||
- If we try to assign string then it will give error. Even if we dont add explicit type annotation `number` it will be still type inferenced as number so only way is to use type annotaion `any`.
|
||||
```ts
|
||||
let age : any = 30;
|
||||
age="31";
|
||||
```
|
||||
|
||||
|
||||
### Better workflow with tsconfig
|
||||
- Automating compiling and running commands by configuration
|
||||
- Initiate config file by
|
||||
`tsc --init`
|
||||
- Configure rootDir and outputDir to appropriate folders. These properties are in compilerOptions in tsconfig.json
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
|
||||
"target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
|
||||
|
||||
|
||||
/* Modules */
|
||||
"module": "commonjs" /* Specify what module code is generated. */,
|
||||
"rootDir": "./src" /* Specify the root folder within your source files. */,
|
||||
"noEmitOnError": true /* Disable emitting files if any type checking errors are reported. */,
|
||||
"outDir": "./dist" /* Specify an output folder for all emitted files. */,
|
||||
|
||||
"esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
|
||||
"forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
|
||||
|
||||
/* Type Checking */
|
||||
"strict": true /* Enable all strict type-checking options. */,
|
||||
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
Also set noEmitOnError as true to stop compiling from ts to js if there are errors.
|
||||
- Now instead of `tsc app.ts` `tsc` is enough but in order to compile to automatically when changed made and file is saved use `tsc --watch` in one instance of terminal. For running too when on save `node --watch dist/app.js`. watch flag for nodejs is only available for node version greater than 18.11.
|
||||
|
||||
### Arrays and Objects
|
||||
- for array containing only string values
|
||||
```ts
|
||||
let names: string[] = ["Mario", "Peach", "Feron"];
|
||||
```
|
||||
- for array containing string or number or boolean values
|
||||
```ts
|
||||
let things: (string | number | boolean)[] = [1, true, "hello"];
|
||||
const t: string | number | boolean = things[0];
|
||||
```
|
||||
|
||||
- **Objects literals**
|
||||
We can not only manage types but fields of objects too using interface like this.
|
||||
```ts
|
||||
let user: { firstname: string; age: number; id: number } = {
|
||||
firstname: "mario",
|
||||
age: 30,
|
||||
id: 1,
|
||||
};
|
||||
```
|
||||
So now all these 3 fields must be defined and no new field can be accessed or added too
|
||||
|
||||
### Functions
|
||||
- Function parameters type must be defined and as for return value of function can be type interfered on basis of return type. if no return then type will be interfered to void
|
||||
```ts
|
||||
function addTwoNumbers(a: number, b: number): number {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
const subtractTowNumbers = (a: number, b: number) : number => {
|
||||
return a + b;
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
### Tuples
|
||||
```ts
|
||||
let person: [string, number, boolean] = ["mario", 30, true];
|
||||
```
|
||||
- here first value of array will be string, 2nd being number and 3rd being boolean and we cant have different type than specified. Purpose of tuple is to return/store multiple values in single variable
|
||||
```ts
|
||||
let xy: [number,number]
|
||||
xy = [74.7,20.1]
|
||||
```
|
||||
- From typesript version 4, these tuple elements can be named too for feedback, they cant be accessed in code by name but its for LSP only
|
||||
```ts
|
||||
let user: [name: string, age: number]
|
||||
|
||||
user= ['peach',25]
|
||||
console.log(user[0])
|
||||
```
|
||||
|
||||
### Interfaces
|
||||
- Ability to create custom types for objects, arrays,etc
|
||||
- For Objects
|
||||
```ts
|
||||
// interfaces
|
||||
interface Author {
|
||||
name: string;
|
||||
avatar: string;
|
||||
}
|
||||
|
||||
const authorOne: Author = { name: "mario", avatar: "img/mario/png" };
|
||||
|
||||
interface Post {
|
||||
title: string;
|
||||
body: string;
|
||||
tags: string[];
|
||||
create_at: Date;
|
||||
author: Author;
|
||||
}
|
||||
|
||||
const newPost: Post = {
|
||||
title: "my first post",
|
||||
body: "something interesting",
|
||||
tags: ["gaming", "tech"],
|
||||
create_at: new Date(),
|
||||
author: authorOne,
|
||||
};
|
||||
|
||||
function createPost(post: Post): void {
|
||||
console.log(`Create post ${post.title} by ${post.author.name}`);
|
||||
}
|
||||
|
||||
createPost(newPost);
|
||||
|
||||
//interfaces in arrays
|
||||
let posts: Post[] = [];
|
||||
posts.push(newPost);
|
||||
```
|
||||
|
||||
### Type aliases
|
||||
- Assigning name to types like tuples and object literals
|
||||
- Example
|
||||
```ts
|
||||
type Rgb = [number, number, number];
|
||||
function getRandomColor(): Rgb {
|
||||
const r = Math.floor(Math.random() * 255);
|
||||
const g = Math.floor(Math.random() * 255);
|
||||
const b = Math.floor(Math.random() * 255);
|
||||
|
||||
return [r, g, b];
|
||||
}
|
||||
|
||||
const colorOne = getRandomColor();
|
||||
const colorTwo = getRandomColor();
|
||||
console.log(colorOne, colorTwo);
|
||||
|
||||
type User = {
|
||||
name: string;
|
||||
score: number;
|
||||
};
|
||||
|
||||
const userOne: User = { name: "mario", score: 75 };
|
||||
|
||||
function formatUser(user: User): void {
|
||||
console.log(`${user.name} has a score of ${user.score} `);
|
||||
}
|
||||
|
||||
formatUser(userOne);
|
||||
formatUser({ name: "yoshi", score: 100 });
|
||||
```
|
||||
|
||||
Union
|
||||
- Union are in C/C++ too and is used to store values of different data type. Unlike structures which is used to store multiple values in same record, union can store only one value and its usecase is when we dont know fixed data type but know range of data type .
|
||||
- Example
|
||||
```ts
|
||||
// unions types
|
||||
|
||||
let someId: number | String
|
||||
|
||||
someId=1
|
||||
someId='2'
|
||||
|
||||
let email : string|null= null
|
||||
|
||||
email = 'mario@netninja.dev'
|
||||
|
||||
type Id = number | string
|
||||
|
||||
function swapIdType(id: Id): Id {
|
||||
// can only use props and methods common to both number and string
|
||||
// parseInt(id) // => this will result in error
|
||||
|
||||
|
||||
|
||||
return id;
|
||||
}
|
||||
```
|
||||
|
||||
### Type Guards
|
||||
- Allows us to methods and props of particular type even it is not available for other type
|
||||
- typescript compiler is smart enough and when we use typeof to create a if block we can use methods of particular type
|
||||
```ts
|
||||
type Id = number | string;
|
||||
|
||||
function swapIdType(id: Id): Id {
|
||||
// can only use props and methods common to both number and string
|
||||
// parseInt(id) // => this will result in error
|
||||
|
||||
// so in order to use methods of particular type type guards is necessary
|
||||
if (typeof id === "string") {
|
||||
// can use string methods
|
||||
return parseInt(id);
|
||||
} else {
|
||||
return id.toString();
|
||||
}
|
||||
}
|
||||
|
||||
const idOne = swapIdType(1);
|
||||
const idTwo = swapIdType("2");
|
||||
|
||||
console.log(idOne, idTwo);
|
||||
```
|
||||
- Tagging interfaces to differenciate them in case there is union of interfaces. Means in interface, we can set propery say type and assign it as same name as of interface. Normally we assign types but in this case we have assigned it as hardcoded string
|
||||
```ts
|
||||
// Union of interfaces
|
||||
interface User3 {
|
||||
type: "User3";
|
||||
username: string;
|
||||
email: string;
|
||||
id: Id;
|
||||
}
|
||||
|
||||
interface Person {
|
||||
type: "Person";
|
||||
firstname: string;
|
||||
age: number;
|
||||
id: Id;
|
||||
}
|
||||
|
||||
function logDetails(value: User3 | Person): void {
|
||||
if (value.type === "User3") {
|
||||
console.log(value.email, value.username);
|
||||
}
|
||||
|
||||
if (value.type === "Person") {
|
||||
console.log(value.firstname, value.age);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**interface for nested objeects**
|
||||
|
||||
Index Signature (Standard Approach)
|
||||
```ts
|
||||
interface UserProfile {
|
||||
name: string;
|
||||
role: string;
|
||||
}
|
||||
|
||||
// This interface accepts ANY key name, but enforces the UserProfile value
|
||||
interface TeamRoles {
|
||||
[roleName: string]: UserProfile;
|
||||
}
|
||||
|
||||
// 🟩 Valid usage: You can name the keys whatever you want
|
||||
const team: TeamRoles = {
|
||||
manager: { name: "Alice", role: "Manager" },
|
||||
lead: { name: "Bob", role: "Tech Lead" },
|
||||
intern: { name: "Charlie", role: "Intern" },
|
||||
consultant: { name: "Diana", role: "Advisor" } // Any new key works seamlessly
|
||||
};
|
||||
|
||||
```
|
||||
or for inline approach
|
||||
|
||||
```ts
|
||||
interface UserProfile {
|
||||
name: string;
|
||||
role: string;
|
||||
}
|
||||
|
||||
// You can use the Record type directly on your variable
|
||||
const flexibleTeam: Record<string, UserProfile> = {
|
||||
manager: { name: "Alice", role: "Manager" },
|
||||
lead: { name: "Bob", role: "Tech Lead" }
|
||||
};
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
Intro
|
||||
https://www.youtube.com/playlist?list=PL4cUxeGkcC9gNhFQgS4edYLqP7LkZcFMN
|
||||
|
||||
Why Typescript
|
||||
- Reducing run time errors
|
||||
- Autocompletion and feedback(code hints)
|
||||
- Custom types : Able to make our own types using interfaces, classea and type aliases
|
||||
|
||||
Installing and Compiling
|
||||
- Install typescript by
|
||||
`npm i -g typscript`
|
||||
- Compile it and run it
|
||||
`tsc app.ts && node app.js`
|
||||
Compiling it with produce js file of same name
|
||||
- Sample code
|
||||
```ts
|
||||
const err = "sasas";
|
||||
|
||||
let str: string;
|
||||
|
||||
str = "1";
|
||||
|
||||
console.log(str);
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
imports and exports
|
||||
|
||||
**exporting types**
|
||||
```ts
|
||||
export interface VideoData {
|
||||
title: string;
|
||||
path: string;
|
||||
description: string;
|
||||
}
|
||||
```
|
||||
|
||||
**importing it**
|
||||
```ts
|
||||
import type { VideoData } from "./types";
|
||||
// or
|
||||
import type types = require("./types");
|
||||
```
|
||||
|
||||
both method can be used as exporting and importing type codes are not included in conveted js file so it dont matter if its es or commonjs
|
||||
|
||||
|
||||
|
||||
### attaching types for imported variables
|
||||
|
||||
|
||||
**for commonjs**
|
||||
|
||||
index.ts
|
||||
```ts
|
||||
const { videoData } = require("./constants") as {
|
||||
videoData: VideoData[];
|
||||
};
|
||||
```
|
||||
|
||||
constants.ts
|
||||
```ts
|
||||
import type { VideoData } from "./types";
|
||||
|
||||
const videoData: VideoData[] = [
|
||||
{
|
||||
title: "fallout new vegas burning sj and dermont",
|
||||
path: "/home/hpmi/Videos/fnv burning sj and dermont.mp4",
|
||||
description: "killing child traffickers brutally in fallout new vegas",
|
||||
},
|
||||
];
|
||||
|
||||
module.exports = { videoData };
|
||||
```
|
||||
|
||||
for esmodule
|
||||
|
||||
```ts
|
||||
export const videoData: VideoData = {
|
||||
title: "test",
|
||||
size: 123,
|
||||
duration: 60
|
||||
};
|
||||
|
||||
import { videoData } from "./constants";
|
||||
```
|
||||
|
||||
no need use `as` as it is automatically inferred in case of esmodule
|
||||
|
||||
|
||||
### importing libraries or inbuilt modules
|
||||
- if importing any modules like `fs` then import it like this
|
||||
```ts
|
||||
const fs = require("fs") as typeof import("fs");
|
||||
```
|
||||
and make sure to have `@types/node` module installed as dev dependency module by
|
||||
`npm install --save-dev @types/node`
|
||||
in case of esmodule simply `import fs from "fs";` will work
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
Uploading file through axios
|
||||
|
||||
```jsx
|
||||
const fs = require('fs');
|
||||
const FormData = require('form-data');
|
||||
const axios = require('axios');
|
||||
|
||||
const file = fs.readFileSync('image_icon.png');
|
||||
const url = 'https://sdrive.app/publicapi/upload';
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', file, { filename: 'image_icon.png' }); // Specify the filename when appending the file
|
||||
|
||||
axios.post(url, formData, {
|
||||
headers: {
|
||||
...formData.getHeaders() // Include headers from FormData
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
console.log('File uploaded successfully:', response.data);
|
||||
// Handle the response data as needed
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
// Handle any errors that occurred during the upload
|
||||
});
|
||||
```
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
Using form-urlencoded
|
||||
https://stackoverflow.com/questions/35325370/how-do-i-post-a-x-www-form-urlencoded-request-using-fetch
|
||||
|
||||
```js
|
||||
const requestBody = new URLSearchParams({
|
||||
client_id: clientId,
|
||||
client_secret: clientSecret,
|
||||
code: code,
|
||||
grant_type: "authorization_code",
|
||||
});
|
||||
|
||||
fetch(apiUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
body: requestBody,
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
// Handle the response data here
|
||||
console.log(data);
|
||||
})
|
||||
.catch(error => {
|
||||
// Handle errors here
|
||||
console.error("Error:", error);
|
||||
});
|
||||
```
|
||||
|
||||
Curl equivalent
|
||||
```bash
|
||||
curl -i -X POST "https://api.box.com/oauth2/token" \
|
||||
-H "content-type: application/x-www-form-urlencoded" \
|
||||
-d "client_id=[CLIENT_ID]" \
|
||||
-d "client_secret=[CLIENT_SECRET]" \
|
||||
-d "code=[CODE]" \
|
||||
-d "grant_type=authorization_code"
|
||||
|
||||
```
|
||||
|
||||
2nd method
|
||||
```js
|
||||
var details = {
|
||||
'userName': 'test@gmail.com',
|
||||
'password': 'Password!',
|
||||
'grant_type': 'password'
|
||||
};
|
||||
|
||||
var formBody = [];
|
||||
for (var property in details) {
|
||||
var encodedKey = encodeURIComponent(property);
|
||||
var encodedValue = encodeURIComponent(details[property]);
|
||||
formBody.push(encodedKey + "=" + encodedValue);
|
||||
}
|
||||
formBody = formBody.join("&");
|
||||
|
||||
fetch('https://example.com/login', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
|
||||
},
|
||||
body: formBody
|
||||
})
|
||||
```
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
blob file download
|
||||
|
||||
```jsx
|
||||
const download=()=>{
|
||||
fetch(`${HOST}`,{
|
||||
|
||||
})
|
||||
.then(res=>res.blob())
|
||||
.then(blob=>{
|
||||
const url = URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
link.download = "extraordinary12.mp3";
|
||||
link.href = url;
|
||||
link.click();
|
||||
})
|
||||
.catch(console.log)
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
creating a text blob
|
||||
```js
|
||||
const textData = "Hello, this is my text content!";
|
||||
const textBlob = new Blob([textData], { type: 'text/plain' });
|
||||
```
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
capacitor
|
||||
|
||||
https://capacitorjs.com/docs/getting-started
|
||||
and
|
||||
https://github.com/fruzelee/capacitor-web2app/tree/main
|
||||
|
||||
in terminal create project
|
||||
|
||||
`npm init @capacitor/app@latest`
|
||||
it will be interactive so select app name, name of directory and app id (com.example.appname)
|
||||
|
||||
`npm i` this will download capacitor/core and capacitor/cli
|
||||
|
||||
|
||||
then
|
||||
**2nd section**
|
||||
|
||||
`npx cap init`
|
||||
|
||||
`npm i @capacitor/android`
|
||||
|
||||
then
|
||||
|
||||
`npm run build`
|
||||
|
||||
`npx cap add android`
|
||||
|
||||
|
||||
instead of `npm init @capacitor/app@latest` use vite to simply create a vanilla one
|
||||
`npm create vite@latest`
|
||||
and then install
|
||||
`npm install @capacitor/cli @capacitor/core`
|
||||
|
||||
then from 2nd section
|
||||
|
||||
|
||||
status bar fix
|
||||
https://capacitorjs.com/docs/apis/status-bar
|
||||
|
||||
install this and then in configs add it and in js file
|
||||
```js
|
||||
import { StatusBar, Style } from '@capacitor/status-bar';
|
||||
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
await StatusBar.setStyle({ style: Style.Dark }); // Forces white icons
|
||||
} catch (e) {
|
||||
console.error("Status bar styling failed", e);
|
||||
}
|
||||
}, 200);
|
||||
```
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
check file type
|
||||
|
||||
```js
|
||||
const isFileImage = (file) => {
|
||||
return file && file["type"].split("/")[0] === "image";
|
||||
};
|
||||
```
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
copy text to clipboard
|
||||
|
||||
```js
|
||||
const transferTextToClipboard = (text) => {
|
||||
const textarea = document.createElement("textarea");
|
||||
textarea.value = text;
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
document.execCommand("copy");
|
||||
document.body.removeChild(textarea);
|
||||
};
|
||||
```
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
file split and merge
|
||||
|
||||
FrontEnd
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<input id="fileInput" type="file" name="" id=""><br>
|
||||
<button onclick="submit()" id="submit">Submit</button>
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
```js
|
||||
const fileEle=document.querySelector("#fileInput")
|
||||
const sliceSize=10*1024*1024 // 10MB
|
||||
|
||||
const submit=()=>{
|
||||
const file= fileEle.files[0]
|
||||
const fileSize=file.size
|
||||
|
||||
let start=0;
|
||||
let end=sliceSize
|
||||
|
||||
const filePieces=[]
|
||||
while(end<=fileSize)
|
||||
{
|
||||
const chunk = file.slice(start,end)
|
||||
filePieces.push(chunk)
|
||||
start=end
|
||||
end+=sliceSize
|
||||
}
|
||||
|
||||
if(start<fileSize)
|
||||
{
|
||||
const chunk = file.slice(start,fileSize)
|
||||
filePieces.push(chunk)
|
||||
}
|
||||
|
||||
console.log('file: ',file)
|
||||
console.log('filePieces: ',filePieces)
|
||||
|
||||
const blob=new Blob(filePieces)
|
||||
const a=document.createElement("a")
|
||||
const link=URL.createObjectURL(blob)
|
||||
a.href= link
|
||||
a.download="something1"
|
||||
a.click()
|
||||
|
||||
|
||||
```
|
||||
99
joplin notion extension/Web Development/Javascript/jquery.md
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
jquery
|
||||
https://api.jquery.com/jQuery.ajax/
|
||||
https://www.w3schools.com/jquery/default.asp
|
||||
|
||||
### Setup
|
||||
Use cdn of google or download compressed from jquery.com and include in script src attribute.
|
||||
|
||||
### Core
|
||||
following is important to wait for document to fully load
|
||||
```js
|
||||
$(document).ready(function(){
|
||||
|
||||
// jQuery methods go here...
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
This is the shorthand way for doing above
|
||||
```js
|
||||
$(function(){
|
||||
|
||||
// jQuery methods go here...
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
### Events
|
||||
```js
|
||||
// will execute click event for these
|
||||
$("p").click();
|
||||
|
||||
// this will attach event listener to click event
|
||||
$("p").click( ()=>{
|
||||
console.log('clicked')
|
||||
} );
|
||||
|
||||
// on will attach event based on name, similar to addEventListener
|
||||
$("p").on("click", function(){
|
||||
$(this).hide();
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Effects
|
||||
|
||||
Once the effect is over then only we have to execute some statements then using callback is useful
|
||||
|
||||
```js
|
||||
|
||||
|
||||
$("button").click(function(){
|
||||
$("p").hide("slow", function(){
|
||||
alert("The paragraph is now hidden");
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
### Method chaining
|
||||
Instead of selecting same elements each time for different methods we can just chain them together
|
||||
```js
|
||||
// three methods chained
|
||||
$("#p1").css("color", "red").slideUp(2000).slideDown(2000);
|
||||
```
|
||||
|
||||
|
||||
|
||||
## HTML Part
|
||||
`text()`, `html()`, `val()`, `attr()`
|
||||
|
||||
|
||||
### Traversing
|
||||
`next()`, `parent()`, `children()`
|
||||
|
||||
### AJAX
|
||||
Asynchronous Javascript and XML
|
||||
`load()` : this will fetch the data and load in the element
|
||||
`get()/post()` : for just fetching request for get and post method respectively
|
||||
`ajax()`. for xhr with ability to send different headers, methods, content-type etc
|
||||
```js
|
||||
$("#div1").load("demo_test.txt");
|
||||
|
||||
$.get("demo_test.asp", function(data, status){
|
||||
alert("Data: " + data + "\nStatus: " + status);
|
||||
});
|
||||
|
||||
$.ajax(url,{
|
||||
"accepts" : "",
|
||||
"contentType": "",
|
||||
method : ""
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
regular expressions
|
||||
|
||||
- dot character in regex dont include newline character so use this `[\s\S]` instead of `.`.
|
||||
eg: `const questionreg = /\.gpt\s+([\s\S]*)/;`
|
||||
- variables in regex
|
||||
```js
|
||||
// variable == 'REGEX'
|
||||
|
||||
// to escape special characters like +,.,etc in variable string
|
||||
function escapeRegExp(string) {
|
||||
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
}
|
||||
|
||||
const variable = <VALUE>
|
||||
|
||||
let re = new RegExp(String.raw`\s${variable}\s`, "g");
|
||||
```
|
||||
- word boundary
|
||||
to search by word `/\bword\b/` instead of `/word/`
|
||||
|
|
@ -0,0 +1,95 @@
|
|||
embedded database
|
||||
|
||||
|
||||
|
||||
**from llm**
|
||||
|
||||
Yes — there are several **SQLite-like databases** that:
|
||||
|
||||
* ✅ Store everything in a **single file**
|
||||
* ✅ Don’t require a central server
|
||||
* ✅ Can store **BSON / document-style data** (instead of strict tables)
|
||||
|
||||
Here are the best options depending on what you want:
|
||||
|
||||
---
|
||||
|
||||
## 1️⃣ **LiteDB** (Very close to what you described)
|
||||
|
||||
* Embedded
|
||||
* Single `.db` file
|
||||
* No server required
|
||||
* Stores data as **BSON documents**
|
||||
* Very similar to MongoDB API
|
||||
* Great for .NET apps
|
||||
|
||||
If you're using C#, this is probably the cleanest choice.
|
||||
|
||||
---
|
||||
|
||||
## 2️⃣ **MongoDB + Embedded Alternatives**
|
||||
|
||||
MongoDB itself requires a server, BUT there are embedded variants:
|
||||
|
||||
### 🔹 **Realm**
|
||||
|
||||
* Embedded
|
||||
* Local file storage
|
||||
* Document-style
|
||||
* Good for mobile apps
|
||||
|
||||
### 🔹 **NeDB**
|
||||
|
||||
* Pure JS
|
||||
* Stores data in a file
|
||||
* Mongo-like API
|
||||
* Good for Node.js apps
|
||||
|
||||
---
|
||||
|
||||
## 3️⃣ **UnQLite**
|
||||
|
||||
Very interesting option:
|
||||
|
||||
* Embedded (like SQLite)
|
||||
* Single file
|
||||
* No server
|
||||
* Key-value + document store
|
||||
* JSON-like storage
|
||||
* Written in C
|
||||
|
||||
This is probably the closest SQLite-style NoSQL engine.
|
||||
|
||||
---
|
||||
|
||||
## 4️⃣ SQLite itself (with JSON)
|
||||
|
||||
Even regular **SQLite** supports:
|
||||
|
||||
* JSON columns
|
||||
* JSON queries
|
||||
* Single-file database
|
||||
* Zero configuration
|
||||
|
||||
If you just need document-style storage without strict schema, SQLite + JSON might already be enough.
|
||||
|
||||
---
|
||||
|
||||
# 🔎 Quick Comparison
|
||||
|
||||
| DB | File-based | Serverless | BSON/Document | Best For |
|
||||
| ------- | ---------- | ---------- | --------------- | ------------ |
|
||||
| LiteDB | ✅ | ✅ | ✅ BSON | .NET apps |
|
||||
| UnQLite | ✅ | ✅ | ✅ JSON-like | C / embedded |
|
||||
| NeDB | ✅ | ✅ | ✅ JSON | Node.js |
|
||||
| SQLite | ✅ | ✅ | JSON (not BSON) | General use |
|
||||
|
||||
---
|
||||
|
||||
If you tell me:
|
||||
|
||||
* What language you’re using
|
||||
* Desktop / web / mobile?
|
||||
* Approx data size?
|
||||
|
||||
I can give you a more precise recommendation.
|
||||
281
joplin notion extension/Web Development/NOSQL/mongodb/Drivers.md
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
Drivers
|
||||
|
||||
- In order to interact with mongodb instead of mongosh or mongodb compass, but in order to interact with application code like node, python,etc we need mongodb drivers for the programming languages as it gives the specific language bindings.
|
||||
These drivers allows us to communicate with mongodb on programatically level.
|
||||
|
||||
db,js
|
||||
```js
|
||||
const { MongoClient } = require("mongodb");
|
||||
|
||||
let dbConnection;
|
||||
|
||||
// the callback function will be called after it connect to the database
|
||||
const connectToDb = (cb) => {
|
||||
// format : protocol://server:PORT/databasename
|
||||
MongoClient.connect("mongodb://localhost:27017/new2")
|
||||
.then((client) => {
|
||||
dbConnection = client.db();
|
||||
return cb();
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
return cb(err);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
connectToDb,
|
||||
getDb: () => dbConnection,
|
||||
};
|
||||
```
|
||||
|
||||
or
|
||||
db.js
|
||||
```js
|
||||
import { MongoClient } from "mongodb";
|
||||
|
||||
const connectToDb = async () => {
|
||||
try {
|
||||
const client = await MongoClient.connect("mongodb://localhost:27017/new2");
|
||||
const dbConnection = client.db();
|
||||
return { dbConnection };
|
||||
} catch (err) {
|
||||
return { err };
|
||||
}
|
||||
};
|
||||
|
||||
export { connectToDb };
|
||||
|
||||
```
|
||||
|
||||
handler.js
|
||||
```js
|
||||
import { connectToDb } from "../_lib/db";
|
||||
|
||||
async function Fn(){
|
||||
|
||||
const { dbConnection, err } = await connectToDb();
|
||||
|
||||
if (err) {
|
||||
console.log("cant connect to db");
|
||||
return new Response("error", { status: 500 });
|
||||
}
|
||||
const commentsCursor = dbConnection
|
||||
.collection("comments")
|
||||
.find({ text: filteredCommentsRegex });
|
||||
const filteredComments = await commentsCursor.toArray();
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- Cursors
|
||||
When we use find method it returns the cursor which points to the set of documents. But in order to get results we need to use cursor methods too like `toArray` and `forEach`. When using shell, shell does that automatically but when coding we have to do things manually. By deafult we can get first 20 documents in shell. for more use the `it` command to get more 20 results.
|
||||
https://www.mongodb.com/docs/drivers/node/v4.1/fundamentals/crud/read-operations/cursor/
|
||||
|
||||
app.js
|
||||
```js
|
||||
const express = require("express");
|
||||
const { connectToDb, getDb } = require("./db");
|
||||
const PORT = process.env.PORT || 8080;
|
||||
|
||||
// init app and middleware
|
||||
const app = express();
|
||||
|
||||
// db connection
|
||||
let db;
|
||||
|
||||
connectToDb((err) => {
|
||||
if (!err) {
|
||||
app.listen(PORT, () => {
|
||||
console.log("app is listening in PORT ", PORT);
|
||||
});
|
||||
db = getDb();
|
||||
}
|
||||
});
|
||||
|
||||
// routes
|
||||
app.get("/books", (req, res) => {
|
||||
let books = [];
|
||||
|
||||
// same as db.books
|
||||
db.collection("books")
|
||||
.find()
|
||||
.sort({ author: 1 })
|
||||
.forEach((book) => books.push(book))
|
||||
.then(() => {
|
||||
res.status(200).json(books);
|
||||
})
|
||||
.catch(() => {
|
||||
res.status(500).json({ error: "Could not fetch the book" });
|
||||
});
|
||||
// res.json({ msg: "welcome to the api" });
|
||||
});
|
||||
```
|
||||
|
||||
other ways are
|
||||
```js
|
||||
const collection = db.collection("books");
|
||||
const cursor = collection.find({});
|
||||
|
||||
// using for await of
|
||||
console.log("async");
|
||||
for await (const doc of cursor) {
|
||||
console.log(doc);
|
||||
}
|
||||
|
||||
// or using toArray
|
||||
const collection = db.collection("books");
|
||||
const cursor = collection.find({});
|
||||
console.log("async");
|
||||
|
||||
const docArray = await cursor.toArray();
|
||||
console.log(docArray);
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
#### Finding single document
|
||||
```js
|
||||
app.get("/books/:id", (req, res) => {
|
||||
const { id } = req.params;
|
||||
|
||||
// if id is not valid then return 400(bad request)
|
||||
if (!ObjectId.isValid(id)) {
|
||||
console.log("Wrong id format");
|
||||
res.status(400).json({ error: "Not a valid doc id" });
|
||||
return;
|
||||
}
|
||||
|
||||
db.collection("books")
|
||||
// as this is not the normal integer or string id so we need to import ObjectId from mongodb module
|
||||
.findOne({ _id: new ObjectId(id) })
|
||||
.then((doc) => {
|
||||
// if doc is null means no such document is found with the given id
|
||||
if (!doc) {
|
||||
res.status(404).json("Not found");
|
||||
return;
|
||||
}
|
||||
res.status(200).json(doc);
|
||||
})
|
||||
.catch((err) => {
|
||||
res.status(500).json("Could not fetch the document");
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**Creating document**
|
||||
```js
|
||||
// post request
|
||||
app.post("/books", (req, res) => {
|
||||
const book = req.body;
|
||||
|
||||
db.collection("books")
|
||||
.insertOne(book)
|
||||
.then((result) => {
|
||||
res.status(201).json(result);
|
||||
})
|
||||
.catch((err) => {
|
||||
res.status(500).json({ err: "Couldn't create a new account" });
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
**Deleting document**
|
||||
```js
|
||||
// delete book by id
|
||||
app.delete("/books/:id", (req, res) => {
|
||||
const { id } = req.params;
|
||||
|
||||
if (ObjectId.isValid(id)) {
|
||||
db.collection("books")
|
||||
.deleteOne({ _id: new ObjectId(id) })
|
||||
.then((result) => {
|
||||
res.status(200).json(result);
|
||||
})
|
||||
.catch((err) => {
|
||||
res.status(500).json({ error: "Could not delete the document" });
|
||||
});
|
||||
} else {
|
||||
res.status(400).json({ error: "not a valid document id" });
|
||||
}
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
**Updating document**
|
||||
```js
|
||||
// update book by id
|
||||
app.patch("/books/:id", (req, res) => {
|
||||
const updates = req.body;
|
||||
|
||||
const { id } = req.params;
|
||||
|
||||
if (ObjectId.isValid(id)) {
|
||||
// as $set operator expects something like {title : 'title1', author : 'author1' }
|
||||
// and body is already in form of the object so directly passing body
|
||||
db.collection("books")
|
||||
.updateOne({ _id: new ObjectId(id) }, { $set: updates })
|
||||
.then((result) => {
|
||||
res.status(200).json(result);
|
||||
})
|
||||
.catch((err) => {
|
||||
res.status(500).json({ error: "Could not update document" });
|
||||
});
|
||||
} else {
|
||||
res.status(400).json({ error: "Not a valid doc id" });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
### Pagination
|
||||
when we get results then it can contain like 1000s of documents so its important to limit it too. so here query parameter is useful.
|
||||
```js
|
||||
// get all books
|
||||
app.get("/books", async (req, res) => {
|
||||
// if there is no parameter named 'p' specfied
|
||||
// then it is assigned as 0
|
||||
const page = req.query.p || 0;
|
||||
// maximum books can be 3 in one page
|
||||
const booksPerPage = 3;
|
||||
|
||||
let books = [];
|
||||
|
||||
// same as db.books
|
||||
db.collection("books")
|
||||
.find()
|
||||
.sort({ author: 1 })
|
||||
.skip(booksPerPage * page)
|
||||
.limit(booksPerPage)
|
||||
.forEach((book) => books.push(book))
|
||||
.then(() => {
|
||||
res.status(200).json(books);
|
||||
})
|
||||
.catch(() => {
|
||||
res.status(500).json({ error: "Could not fetch the book" });
|
||||
});
|
||||
// res.json({ msg: "welcome to the api" });
|
||||
// books = await db.collection("books").find().toArray();
|
||||
// console.log("books: ", books);
|
||||
//
|
||||
|
||||
// const collection = db.collection("books");
|
||||
// const cursor = collection.find({});
|
||||
// console.log("async");
|
||||
//
|
||||
// const docArray = await cursor.toArray();
|
||||
// console.log(docArray);
|
||||
|
||||
//for await (const doc of cursor) {
|
||||
//console.log(doc);
|
||||
//}
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
302
joplin notion extension/Web Development/NOSQL/mongodb/Shell.md
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
Shell
|
||||
|
||||
Type `mongosh` in terminal to start the shell
|
||||
|
||||
- `show databases/dbs` : to show databases
|
||||
- `show collections` : to show collections
|
||||
- `use test2` : switch to test2 database. if test2 doesnt exist it will still switch to it. Once the collection is created in non existent database then that database will be created.
|
||||
- cls : to clear screen
|
||||
- creating variable
|
||||
`var name="yoshi"`
|
||||
then type name in shell it will return `yoshi`
|
||||
`name = "mario"`
|
||||
then typing name in shell will return `mario`
|
||||
- exit : to exit shell
|
||||
|
||||
|
||||
**Creating document**
|
||||
- First add collection using
|
||||
`db.createCollection('col1')` this
|
||||
- Inserting document
|
||||
`db.col1.insertOne({title : "The Color of Magic", author : "Terry Pratchett"})`
|
||||
We dont have `col2` but if we try to insert document in this collection then this connection will be created
|
||||
`db.col2.insertOne({title : "title1"})`
|
||||
for inserting multiple
|
||||
`db.col1.insertMany([{title: "The light fantastic"}, {title: "title2"}])`
|
||||
|
||||
|
||||
**Finding Documents**
|
||||
- Getting all documents
|
||||
`db.col1.find()` this is similar to `select * from col2` in sql.
|
||||
- Using filters in find method
|
||||
- `db.col1.find({author : "Terry Pratchett",
|
||||
title :
|
||||
"The Color of Magic"})`
|
||||
This will print those document with given fields values
|
||||
its equal to `select * from col1 where author = 'Terry Pratchett' and title = 'The Color of Magic'`
|
||||
- `db.col1.find({author : "Terry Pratchett"}, {title: 1, author : 1})`
|
||||
To specify what field we want instead of getting whole document we can specify that in 2nd parameter of find method.
|
||||
this is similar to
|
||||
`select title,author from col1 where author = 'Terry Pratchett'`
|
||||
To get some field but with no filter
|
||||
`db.col1.find({}, {title: 1, author : 1})`
|
||||
just pass empty object as 1st parameter for that
|
||||
- `db.col1.findOne({_id: ObjectId('66590a00d3c92df2cd286ea0')}`
|
||||
to find one document and to pass fields which are keys basically as it will just find first document which matched property.
|
||||
|
||||
|
||||
**Sorting and Limiting Data**
|
||||
- `db.col1.find({author : "Terry Pratchett"}).count()`
|
||||
We can chain methods like this. after getting results, count method will return the count of them
|
||||
- `db.col1.find().limit(2)`
|
||||
this will return the first 2 results
|
||||
- to get 11th to 20th results and not first 20 results use
|
||||
`db.col1.find().skip(10).limit(10)`
|
||||
When you chain skip() and limit(), the method chaining order does not affect the results. The server always applies the skip operation based on the sort order before it applies the limit on how many documents to return.
|
||||
The following code example shows different chaining orders for skip() and limit() that always produce the same query results for the same data set:
|
||||
```js
|
||||
db.myColl.find().sort({_id: 1}).skip(3).limit(6);
|
||||
db.myColl.find().sort({_id: 1}).limit(6).skip(3);
|
||||
```
|
||||
- `db.col1.find().sort({title: 1}).limit(2)`
|
||||
this will sort the documents by title in ascending and return the first 2 results
|
||||
in order to sort by descending order use
|
||||
`db.col1.find().sort({title: -1}).limit(2)`
|
||||
|
||||
|
||||
**Nested Documents**
|
||||
- Instead of creating separate collection we can add them as nested documents too to reduce the complexity too
|
||||
Query
|
||||
```js
|
||||
db.books.insertOne({
|
||||
title: "The Way of Kings",
|
||||
author: "Brandon Sanderson",
|
||||
rating: 9,
|
||||
pages: 320,
|
||||
genres: ["fantasy"],
|
||||
reviews: [{
|
||||
name: "Yoshi",
|
||||
body: "Great book!!!"
|
||||
},
|
||||
{
|
||||
name: "mario",
|
||||
body: "So so"
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
db.books.insertMany(
|
||||
[{title: "The Light Fantastic",
|
||||
author: "Terry Pratchett",
|
||||
pages: 250,
|
||||
rating: 6,
|
||||
genres: ["fantasy", "magic"],
|
||||
reviews: [{name:"luigi", body: "it was pretty good"}, {name: "bowser", body: "loved it!!"}]}, {title: "The Name of the Wind", "author": "Patrick Rothfuss", page: 500, "rating": 10, genres: ["fantasy"], review: [{name: "peach", body: "one of my favs"}]},
|
||||
{title: "The Color of Magic",
|
||||
"author": "Terry Pratchett",
|
||||
page: 350,
|
||||
"rating": 8,
|
||||
genres: ["fantasy", "magic"],
|
||||
review: [{name: "luigi", body: "it was ok"}, {name: "bowser", body: "really good book"}]},
|
||||
{title: "1984",
|
||||
"author": "George Orwell",
|
||||
page: 300,
|
||||
"rating": 6,
|
||||
genres: ["sci-fi", "dystopian"], review: [{name: "peach", body: "not my cup of tea"}, {name: "mario", body: "meh"}]}
|
||||
])
|
||||
|
||||
```
|
||||
|
||||
**Operations and Complex Queries**
|
||||
- All operators begin with `$` sign
|
||||
- gt : greater than
|
||||
`db.books.find({rating : {$gt : 8}})`
|
||||
All books with rating greater than 8
|
||||
- gte : greater than or equal to
|
||||
- lt : lesser than
|
||||
- lte : lesser than or equal to
|
||||
- or
|
||||
`db.books.find({$or : [ {rating : 7}, {rating: 9} ]})`
|
||||
this will return those books whose rating is either 7 or 9.
|
||||
`db.books.find({ $or : [{rating : 7}, {author: "Terry Pratchett" } ] })`
|
||||
- last example
|
||||
`db.books.find( {$or : [{pages: {$lt : 300}}, {pages: {$gt: 400} } ]} )`
|
||||
this will return books with pages less than 300 and pages greater than 400.
|
||||
- for accessing nested objects
|
||||
```js
|
||||
db.col1.insertOne(
|
||||
{
|
||||
"obj": {
|
||||
"data": "lorem"
|
||||
}
|
||||
}
|
||||
)
|
||||
```
|
||||
`db.col1.find( { "obj.data": "lorem" } )`
|
||||
- Summary
|
||||
```
|
||||
- Name
|
||||
= Description
|
||||
|
||||
$eq
|
||||
Matches values that are equal to a specified value.
|
||||
|
||||
$gt
|
||||
Matches values that are greater than a specified value.
|
||||
|
||||
$gte
|
||||
Matches values that are greater than or equal to a specified value.
|
||||
|
||||
$in
|
||||
Matches any of the values specified in an array.
|
||||
|
||||
$lt
|
||||
Matches values that are less than a specified value.
|
||||
|
||||
$lte
|
||||
Matches values that are less than or equal to a specified value.
|
||||
|
||||
$ne
|
||||
Matches all values that are not equal to a specified value.
|
||||
|
||||
$nin
|
||||
Matches none of the values specified in an array.
|
||||
|
||||
|
||||
|
||||
Logical
|
||||
|
||||
- Name
|
||||
= Description
|
||||
|
||||
$and
|
||||
Joins query clauses with a logical AND returns all documents that match the conditions of both clauses.
|
||||
|
||||
$not
|
||||
Inverts the effect of a query expression and returns documents that do not match the query expression.
|
||||
|
||||
$nor
|
||||
Joins query clauses with a logical NOR returns all documents that fail to match both clauses.
|
||||
|
||||
$or
|
||||
Joins query clauses with a logical OR returns all documents that match the conditions of either clause.
|
||||
```
|
||||
|
||||
|
||||
**in and nin operator**
|
||||
- in :
|
||||
`db.books.find({rating : {$in : [7,8,9] }})` : return results whose ratings are either of the values in array. Same can be done with `or`
|
||||
`db.books.find({$or : [ {rating: 7},{rating: 8},{rating: 9} ] })`
|
||||
- nin :
|
||||
`db.books.find({rating : {$nin : [7,8,9] }})` : return results whose ratings are neither of the values in array. Same can be done with `nor`
|
||||
`db.books.find({$nor : [ {rating: 7},{rating: 8},{rating: 9} ] })`
|
||||
|
||||
|
||||
**Querying Arrays**
|
||||
- Match found
|
||||
`db.books.find({genres: "fantasy"})`
|
||||
this will return the documents whose field genre contains fantasy in its array. genre may be only fantasy or it can have more genres too but `fantasy` must be included.
|
||||
- Only match
|
||||
As genre is array so to get the only match
|
||||
`db.books.find({genres: ["fantasy"]})`
|
||||
this will return documents with field containing this value which is `fantasy` only. we can have magic too so it will return those which contains values `fantasy` and `magic` too.
|
||||
eg 2: `db.books.find({genres: ["fantasy","magic"]})`
|
||||
- Match found for given set(all operator)
|
||||
Only match will only return those with specified but if we want to include those with given set(they can have more but given set must be included) then
|
||||
`db.books.find({genres: {$all: ["fantasy", "sci-fi"]} })`
|
||||
- Match found of either of given values
|
||||
for example if we need those which contains atleast magic or atleast sci-fi in one of them
|
||||
`db.books.find({ $or: [ {genres: "magic"}, {genres : "sci-fi"} ] })`
|
||||
- Matching nested documents
|
||||
review field contains documents itself. Suppose we wanna query those documents whose review have documnets with field name and we want specific name too like 'luigi'(documnets where reviews is posted by user 'luigi') then
|
||||
`db.books.find({"review.name": "luigi"})`
|
||||
|
||||
|
||||
**Deleting Documents**
|
||||
- `db.books.deleteOne({_id : ObjectId('66592602d3c92df2cd286ea5')})`
|
||||
this will delete one document with the given `_id` value. we can have different field too but since id is unique so it is recommended.
|
||||
- `db.books.deleteMany({author : "Terry Pratchett"})`
|
||||
Unlike deleteOne which will delete only one document and stop its search, this will delete all the documents containing the given value of field
|
||||
|
||||
|
||||
**Updating Documents**
|
||||
- `db.books.updateOne( {_id : ObjectId('66592602d3c92df2cd286ea5') }, {$set : {rating : 8, pages : 350}} )`
|
||||
set operator is used to change the values of fields of document whose id is ` ObjectId('66592602d3c92df2cd286ea5')`.
|
||||
- `db.books.updateMany( {author : "Terry Pratchett" }, {$set : {author : "Terry Pratchet"}} )`
|
||||
to update records of given field. unlike updateOne it will check for every records and wont stop after first match is found.
|
||||
- inc operator
|
||||
`db.books.updateOne( {_id: ObjectId('66592602d3c92df2cd286ea2')}, {$inc : {pages : 2} } )`
|
||||
unlike set it doesnt replace but increment it so in case we dont know the value and wanna increment it then we can use this
|
||||
To decrement it we can pass just negative number like `-2`
|
||||
- push and pull
|
||||
to add or delete contents in array
|
||||
`db.books.updateOne( {_id: ObjectId('66592602d3c92df2cd286ea2')}, {$pull : {genres : "fantasy"} } )`
|
||||
to delete `fantasy` from array of genres
|
||||
`db.books.updateOne( {_id: ObjectId('66592602d3c92df2cd286ea2')}, {$push : {genres : "fantasy"} } )`
|
||||
to add `fantasy` in array of genres
|
||||
- each
|
||||
with push and pull we can only do it for one element of array. for multiple elements we have to each operator
|
||||
`db.books.updateOne( {_id: ObjectId('66592602d3c92df2cd286ea2')}, {$push : {genres : {$each : ["1","2"] } } } )`
|
||||
this will push '1' and '2' in array of genres field.
|
||||
- pullAll
|
||||
to do same with pull we cant use each but need to use pullAll
|
||||
`db.books.updateOne( {_id: ObjectId('66592602d3c92df2cd286ea2')}, {$pullAll : {genres : ["1","2"] } } )`
|
||||
- to update nested document
|
||||
To update the name from "Yoshi" to "Yosh" in the MongoDB document, you can use the updateOne() method with a filter to match the document and an update operation to modify the nested field within the "reviews" array. Here's an example of how you can do it using MongoDB's shell:
|
||||
```js
|
||||
db.books.updateOne(
|
||||
{ "reviews.name": "Yoshi" }, // Filter to match the document containing the review with name "Yoshi"
|
||||
{ $set: { "reviews.$.name": "Yosh" } } // Update operation to set the name to "Yosh"
|
||||
)
|
||||
|
||||
```
|
||||
So `reviews.$.name` refers to the "name" field within the matched element of the "reviews" array. It ensures that only the specific review that matched the query condition (in this case, the review with the name "Yoshi") will have its "name" field updated to "Yosh".
|
||||
so $ is positional operator
|
||||
Similary to change array element use
|
||||
```js
|
||||
db.books.updateOne(
|
||||
{ "genres": "fantasy" }, // Filter to match the document containing "fantasy" in the genres array
|
||||
{ $set: { "genres.$": "fantas" } } // Update operation to set the value to "fantas"
|
||||
)
|
||||
|
||||
```
|
||||
|
||||
### Indexes
|
||||
- By default when we find a document through a filter which is not id it scans all documents. Id field is already indexed. But we can also set another field's values as index too by creating a separate index
|
||||

|
||||
- Its simlar to caching/indexing in order to get results faster
|
||||
- One thing to be noted that creating index is not appropriate always when the field is write heavy instead of read heavy bcz whenever value is modified or new document is added indexed needs to be updated so it can be costly too if field is write heavy.
|
||||
- Checking evaluation stats
|
||||
`db.books.find({ rating : 8 }).explain('executionStats')`
|
||||
this will return totalDocsExamined as number of all documents
|
||||
- Creating index
|
||||
`db.books.createIndex({rating : 8})`
|
||||
- Print the list of indexed
|
||||
`db.books.getIndexes()`
|
||||
Now when checking evaluation stat it will return totalDocsExamined as number of documents where rating of 8 exist
|
||||
- Deleting index
|
||||
`db.books.dropIndex({rating : 8})`
|
||||
|
||||
|
||||
### Improrting and exporting documents
|
||||
- To export collection named `books` from database named `new2`
|
||||
`mongoexport --db new2 --collection books --out ~/Desktop/upload/books.json`
|
||||
- To import collection named `books` from to database `new3`
|
||||
`mongoimport --db new3 --collection books --file ~/Desktop/upload/books.json`
|
||||
- to export whole database named `new2`
|
||||
`mongodump -d new2 -o ~/Desktop/upload/new2`
|
||||
- to import database from the dump folder
|
||||
`mongorestore -d new4 ~/Desktop/upload/new2/new2/`
|
||||
- Exporting with certain query
|
||||
`mongosh new2 --quiet --eval 'DBQuery.shellBatchSize = 2000; db.books.find({}).limit(2000).toArray()' > books.json`
|
||||
as DbQuery.shellBatcjSize is depreciated so use this
|
||||
`mongosh new2 --quiet --eval 'config.set("displayBatchSize", 2000); db.books.find({}).limit(2000).toArray()' > books.json`
|
||||
or with a script file containing query
|
||||
file containing following statement
|
||||
`printjson(db.books.find({}).limit(2000).toArray() )`
|
||||
so use this command
|
||||
`mongosh new2 --eval 'load("./Desktop/upload/query.js")'`
|
||||
|
||||
**for remote databases use**
|
||||
- `mongoexport --uri "mongodb+srv://<username>:<password>@testcluster.7kxguvp.mongodb.net/" --db sample_mflix --collection comments -o ~/Desktop/upload/comments.json`
|
||||
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
Theory
|
||||
https://www.youtube.com/playlist?list=PL4cUxeGkcC9h77dJ-QJlwGlZlTd4ecZOA
|
||||
|
||||
- relational database
|
||||
1 author can have many books whose information are stored in the other table named Books.
|
||||

|
||||
So we have rows,columns, table and joining
|
||||
Columns is property
|
||||
and we use sql queries to use them
|
||||
|
||||
|
||||
- non relational database
|
||||
Here instead of rows, columns and tables we use collections and documents
|
||||
Each collection store a specific type of data record like users, authors and books.These records inside collections are called documents
|
||||
So users is collection unlike table in sql. and instead of containing columns and rows it contains document which is more like js object
|
||||

|
||||
Here author field has nested object. in sql we would have to use other table for that.
|
||||
|
||||
**Installation**
|
||||
- In arch use
|
||||
`yay -S mongodb-bin` this will install mongodb server and mongodb shell. Make sure to start mongodb service too by
|
||||
`systemctl start mongodb`
|
||||
also install mongodb-tools. `mongodb-org-tools` in case of debian and `mongodb-tools-bin` from aur in case of arch. it is for import, export and other diagonistic tools
|
||||
|
||||
- in linux mint/ubuntu
|
||||
https://www.mongodb.com/docs/v7.0/tutorial/install-mongodb-on-ubuntu/#std-label-install-mdb-community-ubuntu
|
||||
|
||||
|
||||
**Collections and Documents**
|
||||

|
||||
Mongodb stores data in BSON which is Binary JSON and returns result in JSON.
|
||||
Each document has a property `_id` which is assigned automatically by mongodb and its data type is 'ObjectId'.
|
||||
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
mongoose
|
||||
https://mongoosejs.com/docs/api/model.html
|
||||
|
||||
|
||||
- findall
|
||||
`const tasks = await Task.find()`
|
||||
|
||||
- sorting
|
||||
`const tasks = await Task.find().sort({complexity: 1})`
|
||||
- patching
|
||||
`const updatedTask = await Task.findByIdAndUpdate(taskID,{complexity},{new: true})`
|
||||
- inserting using save method
|
||||
```js
|
||||
const newTask = new Task({title,complexity})
|
||||
const savedTask = await newTask.save()
|
||||
```
|
||||
- deleting
|
||||
`const deletedTask = await Task.findByIdAndDelete(taskID)`
|
||||
|
||||
|
||||
basic program
|
||||
|
||||
```js
|
||||
const express = require('express')
|
||||
|
||||
const mongoose = require('mongoose')
|
||||
const cors = require('cors')
|
||||
require('dotenv').config()
|
||||
|
||||
const app = express()
|
||||
app.use(cors())
|
||||
app.use(express.json())
|
||||
|
||||
const PORT = process.env.PORT || 5000
|
||||
const MONGO_URI= process.env.MONGO_URI || 'mongodb://127.0.0.1:27017/merndb'
|
||||
|
||||
mongoose.connect(MONGO_URI).then(()=> console.log('mongodb connnected')).catch(err=>console.log('mongodb connection error'))
|
||||
|
||||
const TaskSchema = new mongoose.Schema({title: {type: String, require: true}})
|
||||
const Task = mongoose.model('Task',TaskSchema)
|
||||
|
||||
app.get('/api/tasks', async (req,res)=>{
|
||||
const tasks = await Task.find();
|
||||
res.json(tasks);
|
||||
|
||||
|
||||
})
|
||||
|
||||
|
||||
app.post('/api/tasks', async (req,res)=>{
|
||||
const newTask = new Task({title : req.body.title})
|
||||
const savedTask = await newTask.save()
|
||||
res.status(201).json(savedTask)
|
||||
} )
|
||||
|
||||
app.listen(PORT,()=> console.log(`Server running on port ${PORT}`) )
|
||||
```
|
||||
40
joplin notion extension/Web Development/Neovim/Basics 3.md
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
Basics 3
|
||||
|
||||
- cursor location
|
||||
`<C-g>` to show location in file and file status. It means 'Ctrl+G'.
|
||||
`gg` is used to to start of file like using Ctrl+Home in gui editors
|
||||
`G` for end of file
|
||||
To go to specific line number `<line_number>G`. Eg: for line number 123 type `123G`.
|
||||
- Search command
|
||||
To search word type `/<word>`. To search error type `/error`. Then type `n` to go to next search and `N` to go to opposite one.
|
||||
`/` is used to search in direction from up to down. To search in direction from down to up use `?`.
|
||||
Note: To remove highlighting of previous search type `:let @/ = ""` or use `:noh`
|
||||
Reference: https://stackoverflow.com/questions/657447/vim-clear-last-search-highlighting
|
||||
To go back to where you came from press `<C-o>`.
|
||||
(keep `<Ctrl>` pressed down while pressing the letter `o`).
|
||||
Repeat to go back further. `<C-i>`{normal} goes forward.
|
||||
- Matching parenthesis search
|
||||
Type `%` to find a matching `)`,`]`, or `}`.
|
||||
Place the cursor on parenthesis For eg on `(`
|
||||
tree (they r here [done] )
|
||||
Then type `%`. it will move to `)` . Now type `%` again and it will move back to `(`.
|
||||
|
||||
- Substitute command
|
||||
Type `:s/old/new/g` to substitute "new" for "old".
|
||||
Move the cursor to line where subtitution needed to be take place. If g is not used then only first occurence will be substituted instead of all occurences of current line.
|
||||
`:201,204s/old/new/g` : replace old with new from line 201 to 204
|
||||
For whole file
|
||||
`%s/old/new/g`
|
||||
For whole file but with prompt
|
||||
`%s/old/new/gc`
|
||||
|
||||
- Executing external commands
|
||||
`:!ls` or `:!pwd`
|
||||
- Selecting text to write
|
||||
To start selecting text press `v` then move cursor right and down to area u want ti selected. To finish selecting a text type colon `:` `'<,'>` will appear now just type `w` and file name where u want to be saved
|
||||
`'<,'>w Test.txt`. Now selected text will be saved in filename 'Test.txt'
|
||||
|
||||
- Retrieving and merging file
|
||||
Move cursor to desired line and type
|
||||
`:r TEST` :This will copy contents of file TEST to current position
|
||||
`:r !ls` : This will copy output of commands ls to current position
|
||||
44
joplin notion extension/Web Development/Neovim/Basics 4.md
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
Basics 4
|
||||
|
||||
- Open a line
|
||||
To insert empty line below cursor and toggle insert mode type `o`
|
||||
To insert empty line above cursor and toggle insert mode type `O`(capital o)
|
||||
- Append command
|
||||
Normally when we insert text, its inserted before the cursor so in the word say `li`. If cursor at `i`. and we press i then type q then we have `lqi` so using
|
||||
`a` first cursor is moved one character right and then goes to insert mode so if after using `a` we type q, then we have `liq`.
|
||||
- Replace Mode
|
||||
Toggled by `R`(capital R). if it is on word say `the` and cursor is at beginning ie `T` then when we type Say then it will become `Say` not SayThe.
|
||||
NOTE: Replace mode is like Insert mode, but every typed character
|
||||
replaces an existing character
|
||||
- Copy and paste
|
||||
Highlight the text to be copied. We can do this by going to visual mode by pressing `v` and moving cursor to select text. Press Esc to escape visual mode. Press `y` to copy and `p` tp paste.
|
||||
y here stands for yank
|
||||
p stands for put
|
||||
|
||||
- Set option
|
||||
To alter some settings in nvim
|
||||
when searching to ignore case type `:set ic`
|
||||
To turn off ignore case type `:set noic`
|
||||
To toggle ignorecase setting `:set invic`
|
||||
NOTE: If you want to ignore case for just one search command, use `\c`
|
||||
in the phrase: `/ignore\c`
|
||||
- Switch between windows
|
||||
`<C-w><C-w>` means Ctrl+w 2 times
|
||||
|
||||
- Creating startup script
|
||||
Neovim is a very configurable editor. You can customise it any way you like.
|
||||
To start using more features create an "init.vim" file.
|
||||
1. Start editing the "init.vim" file.
|
||||
|
||||
`:call mkdir(stdpath('config'),'p')`
|
||||
`:exe 'edit' stdpath('config').'/init.vim'`
|
||||
2. Write the file with:
|
||||
`:w`
|
||||
|
||||
- Auto Completion
|
||||
When typing any command to get the listed list of commands begining with whatever typed , press `<C-d>`. Now press `tab` to auto-complete it.
|
||||
Eg: If we type `:e` then pressing Ctrl+d witll list commands starting from `e` and pressing tab will autocomplete with first result
|
||||
- Switching between files
|
||||
When u have opened nvim in folder and that folder contains some files then use the relative path to access them by
|
||||
`:e main.c` or `:e Makefile`
|
||||
|
||||
42
joplin notion extension/Web Development/Neovim/Basics.md
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
Basics
|
||||
|
||||
|
||||
↑
|
||||
k Hint: The `h`{normal} key is at the left and moves left.
|
||||
← h l → The `l`{normal} key is at the right and moves right.
|
||||
j The `j`{normal} key looks like a down arrow.
|
||||
↓
|
||||
h (left) j (down) k (up) l (right)
|
||||
|
||||
|
||||
|
||||
- Install xclip for x11 Display server
|
||||
`pacman -S xclip`
|
||||
For others
|
||||
- g:clipboard
|
||||
- pbcopy, pbpaste (macOS)
|
||||
- wl-copy, wl-paste (if $WAYLAND_DISPLAY is set)
|
||||
- waycopy, waypaste (if $WAYLAND_DISPLAY is set)
|
||||
- xclip (if $DISPLAY is set)
|
||||
- xsel (if $DISPLAY is set)
|
||||
- lemonade (for SSH) https://github.com/pocke/lemonade
|
||||
- doitclient (for SSH) https://www.chiark.greenend.org.uk/~sgtatham/doit/
|
||||
- win32yank (Windows)
|
||||
- termux (via termux-clipboard-set, termux-clipboard-set)
|
||||
- tmux (if $TMUX is set)
|
||||
|
||||
- To maximize the current editor section use Ctrl+w then press 'o'
|
||||
- To close the current editor type `:close`
|
||||
- Closing it
|
||||
`:q`
|
||||
Closing it and ignore any changes made
|
||||
`qa!`
|
||||
- Deleting character under mouse:
|
||||
Press x button
|
||||
- Inserting character : i button
|
||||
- Appending character : A button
|
||||
As it is capital A so make sure to 'shift+a' or 'Capslock then a'.
|
||||
- Saving file
|
||||
:w : saving file
|
||||
:wq : saving and closing
|
||||
|
||||
84
joplin notion extension/Web Development/Neovim/Basics2.md
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
Basics2
|
||||
|
||||
- To delete a word type `dw`
|
||||
|
||||
- deleting from left to right(end of line) type `d$`
|
||||
|
||||
- Many commands that change text are made from an [operator](/tmp/.mount_JoplinZ52JzN/resources/app.asar/operator "operator") and a [motion](/tmp/.mount_JoplinZ52JzN/resources/app.asar/navigation "navigation").
|
||||
The format for a delete command with the [d](/tmp/.mount_JoplinZ52JzN/resources/app.asar/d "d") delete operator is as follows:
|
||||
|
||||
d motion
|
||||
|
||||
Where:
|
||||
d - is the delete operator.
|
||||
motion - is what the operator will operate on (listed below).
|
||||
|
||||
A short list of motions:
|
||||
|
||||
```text
|
||||
w - until the start of the next word, EXCLUDING its first character.
|
||||
e - to the end of the current word, INCLUDING the last character.
|
||||
$ - to the end of the line, INCLUDING the last character.
|
||||
```
|
||||
|
||||
- Number itself can be used to move cursor
|
||||
`2w` can be used to move cursor 2 words forward and at start of the 2nd word next to it
|
||||
`2e` like 2w but instead of first character it moves to last character of the word
|
||||
`0` works like home button ie to move to beginning of line
|
||||
Eg:
|
||||
Before using `2w` cursor is on
|
||||
==L==orem ipsum try it
|
||||
After using it
|
||||
Lorem ipsum ==t==ry it
|
||||
|
||||
Before using `2e` cursor is on
|
||||
==L==orem ipsum try it
|
||||
After using it
|
||||
Lorem ipsum tr==y== it
|
||||
|
||||
- Now using `operator number motion` syntax
|
||||
`d2w` : will delete 2 words ie current word and next word
|
||||
with syntax `number operator motion`
|
||||
`dd`: will delete the whole current line
|
||||
`2dd` : will delete 2 lines ie current and next one
|
||||
|
||||
- Undo command
|
||||
Loprem ipsum try it
|
||||
Some changes like
|
||||
Loorem ipsum try it
|
||||
`u` : to undo previous change
|
||||
Loprem ipsum try it
|
||||
Some more changes like
|
||||
Looooorem ipsi bipsy try it
|
||||
So many changes r there
|
||||
`U` : to undo all changes for current line and bring back to its original state
|
||||
Loprem ipsum try it
|
||||
Redo : `<C-r>` Ctrl+R
|
||||
|
||||
- Put command
|
||||
For example if u delete a line using `dd` than that line will be stored in neovim register
|
||||
then we can put the line below the cursor using `p`
|
||||
Before using dd for a
|
||||
a. 1st line
|
||||
b. 2nd line
|
||||
After using it
|
||||
b. 2nd line
|
||||
then on moving cursor to line b and using `p`
|
||||
b. 2nd line
|
||||
a. 1st line
|
||||
Note: `p` is used to put down/next to but `P` is used to put it up/before to it
|
||||
|
||||
- Replace command
|
||||
`r` will used for replacing a character
|
||||
Eg : Lor==a==m
|
||||
Now pressing `r` then `e`
|
||||
=> Lor==e==m
|
||||
- Change
|
||||
Like using insert or i but with a variation ie before going to insert word it will delete the corrent word. , type `ce`
|
||||
Its a combination `de` and `i`
|
||||
c is like d actually with diffrence that it will put into insert mode after deletion
|
||||
so `c2w` is `d2w`+`i`.
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,362 @@
|
|||
Configuration neovim pt2(Another way)
|
||||
https://www.youtube.com/watch?v=CVCBHHFXWNE
|
||||
https://files.catbox.moe/hyab70.mp4
|
||||
https://github.com/NvChad/NvChad
|
||||
|
||||
|
||||
[nvim.zip](../../../_resources/nvim.zip)
|
||||
|
||||
|
||||
|
||||
- Cloning to nvim
|
||||
`git clone https://github.com/NvChad/NvChad ~/.config/nvim depth 1`
|
||||
- Initializing
|
||||
Restart neovim and press N when ask to bout installation of something custom.Then wait for some installation.
|
||||
- Choose Theme
|
||||
Press space and type `th` to select through themes
|
||||
- Open TreeView
|
||||
Using `<C-N>`(Ctrl+N)
|
||||
- Switch between trreeview and normal text file
|
||||
`<C-H>` to go to treeview. `<C-L>` to go to normal text area
|
||||
- Create new file with treeview
|
||||
Type `a` to create new file when inside treeview
|
||||
|
||||
- Installing LSP
|
||||
In `~/.config/nvim/lua/custom/chadrc.lua` add this before `return M` line
|
||||
`M.plugins="custom.plugins"`
|
||||
Then create `~/.config/nvim/lua/custom/plugins.lua` and add
|
||||
```lua
|
||||
local plugins={
|
||||
{
|
||||
"williamboman/mason.nvim",
|
||||
opts={
|
||||
ensure_installed={
|
||||
"typescript-language-server"
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
return plugins
|
||||
```
|
||||
And add tsserver inside ensure_installed like this and restart nvim and install it using the command `MasonInstallAll`.
|
||||
- Initializing nvim-lspconfig
|
||||
Add more like this
|
||||
```lua
|
||||
local plugins={
|
||||
{
|
||||
"williamboman/mason.nvim",
|
||||
opts={
|
||||
ensure_installed={
|
||||
"typescript-language-server"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"neovim/nvim-lspconfig",
|
||||
config= function ()
|
||||
require "plugins.configs.lspconfig"
|
||||
require "custom.configs.lspconfig"
|
||||
end,
|
||||
},
|
||||
}
|
||||
return plugins
|
||||
```
|
||||
Create `~/.config/nvim/lua/custom/configs/lspconfig.lua` and open it. Here we store all our lsp configurations
|
||||
```lua
|
||||
-- Default nvchad configs
|
||||
local config=require("plugins.configs.lspconfig")
|
||||
-- Other default configs
|
||||
local on_attach =config.on_attach
|
||||
local capabilities =config.capabilities
|
||||
|
||||
-- For tsserver
|
||||
local lspconfig =require("lspconfig")
|
||||
|
||||
-- Here suggestions are set to be disabled to avoid useless clutter as useless suggestions were there
|
||||
lspconfig.tsserver.setup{
|
||||
on_attach=on_attach,
|
||||
capabilities=capabilities,
|
||||
init_options={
|
||||
preferences={
|
||||
disableSuggestions=true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- Linting
|
||||
In `~/.config/nvim/lua/custom/plugins.lua` add eslint-lsp like this
|
||||
```
|
||||
ensure_installed={
|
||||
"eslint-lsp",
|
||||
"typescript-language-server"
|
||||
}
|
||||
|
||||
```
|
||||
Using nvim-lint by adding entry in plugins.lua like this
|
||||
```lua
|
||||
local plugins={
|
||||
{
|
||||
"mfussenegger/nvim-lint",
|
||||
event="VeryLazy",
|
||||
config=function ()
|
||||
require "custom.configs.lint"
|
||||
end
|
||||
},
|
||||
{
|
||||
"williamboman/mason.nvim",
|
||||
opts={
|
||||
ensure_installed={
|
||||
"eslint-lsp",
|
||||
"typescript-language-server"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"neovim/nvim-lspconfig",
|
||||
config= function ()
|
||||
require "plugins.configs.lspconfig"
|
||||
require "custom.configs.lspconfig"
|
||||
end,
|
||||
},
|
||||
}
|
||||
return plugins
|
||||
```
|
||||
Create `~/.config/nvim/lua/custom/configs/lint.lua` and open it. Type this
|
||||
```lua
|
||||
require('lint').linters_by_ft={
|
||||
javascript={'eslint'},
|
||||
typescript={'eslint'}
|
||||
}
|
||||
|
||||
vim.api.nvim_create_autocmd({"BufWritePost"},{
|
||||
callback=function ()
|
||||
require("lint").try_lint()
|
||||
end,
|
||||
})
|
||||
|
||||
```
|
||||
Before working in project install eslint config in it by this
|
||||
`npm init @eslint/config`
|
||||
|
||||
- Auto-formatting
|
||||
Add "prettier" in ensure_installed section. Then add entry like this `plugins.lua`
|
||||
```lua
|
||||
local plugins={
|
||||
{
|
||||
"mhartington/formatter.nvim",
|
||||
event="VeryLazy",
|
||||
opts = function ()
|
||||
return require "custom.configs.formatter"
|
||||
end
|
||||
},
|
||||
{
|
||||
"mfussenegger/nvim-lint",
|
||||
event="VeryLazy",
|
||||
config=function ()
|
||||
require "custom.configs.lint"
|
||||
end
|
||||
},
|
||||
{
|
||||
"williamboman/mason.nvim",
|
||||
opts={
|
||||
ensure_installed={
|
||||
"eslint-lsp",
|
||||
"prettier",
|
||||
"typescript-language-server"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"neovim/nvim-lspconfig",
|
||||
config= function ()
|
||||
require "plugins.configs.lspconfig"
|
||||
require "custom.configs.lspconfig"
|
||||
end,
|
||||
},
|
||||
}
|
||||
return plugins
|
||||
```
|
||||
Create `~/.config/nvim/lua/custom/configs/formatter.lua` and open it. Type this
|
||||
```lua
|
||||
local M={
|
||||
filetype={
|
||||
javascript={
|
||||
require("formatter.filetypes.javascript").prettier
|
||||
},
|
||||
typescript={
|
||||
require("formatter.filetypes.typescript").prettier
|
||||
},
|
||||
javascriptreact = {
|
||||
require("formatter.filetypes.javascript").prettier
|
||||
},
|
||||
typescriptreact = {
|
||||
require("formatter.filetypes.typescript").prettier
|
||||
},
|
||||
["*"]={
|
||||
require("formatter.filetypes.any").remove_trailing_whitespace
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vim.api.nvim_create_autocmd({"BufWritePost"},{
|
||||
command = "FormatWriteLock"
|
||||
})
|
||||
|
||||
return M
|
||||
```
|
||||
|
||||
- null ls(optional)
|
||||
in `plugins.lua` file remove the entries for formatter and lint and instead add this entry
|
||||
```lua
|
||||
{
|
||||
"jose-elias-alvarez/null-ls.nvim",
|
||||
event="VeryLazy",
|
||||
opts= function()
|
||||
return require "custom.configs.null-ls"
|
||||
end,
|
||||
},
|
||||
```
|
||||
Create `~/.config/nvim/lua/custom/configs/null-ls.lua` and open it. Type this
|
||||
```lua
|
||||
local augroup=vim.api.nvim_create_augroup("LspFormatting",{})
|
||||
local null_ls=require("null-ls")
|
||||
|
||||
local opts={
|
||||
sources= {
|
||||
null_ls.builtins.diagonstics.eslint,
|
||||
null_ls.builtins.formatting.prettier,
|
||||
},
|
||||
on_attach= function(client,bufnr)
|
||||
if client.supports_method("textDocument/formatting") then
|
||||
vim.api.nvim_clear_autocmds({
|
||||
group=augroup,
|
||||
buffer=bufnr,
|
||||
})
|
||||
vim.api.nvim_create_autocmd("BufWritePre",{
|
||||
group=augroup,
|
||||
buffer=bufnr,
|
||||
callback=function()
|
||||
vim.lsp.buf.format({bufnr=bufnr})
|
||||
end,
|
||||
})
|
||||
}
|
||||
```
|
||||
Advantage : Linter runs dynamiclly rather than saving a file
|
||||
- Debugger
|
||||
We will use DAP(Debug Adapter Protocol)
|
||||
Add "js-debug-adapter" in ensure_installed section.
|
||||
Add this entry too in `plugins.lua` section
|
||||
```lua
|
||||
{
|
||||
"mfussenegger/nvim-dap",
|
||||
config=function ()
|
||||
require "custom.configs.dap"
|
||||
end
|
||||
},
|
||||
|
||||
```
|
||||
Create `~/.config/nvim/lua/custom/configs/dap.lua` and open it. Type this
|
||||
```lua
|
||||
local dap= require("dap")
|
||||
|
||||
dap.adapters["pwa-node"]={
|
||||
type="server",
|
||||
host="127.0.0.1",
|
||||
port=8123,
|
||||
executable={
|
||||
command="js-debug-adapter",
|
||||
}
|
||||
}
|
||||
|
||||
for _, language in ipairs {"typescript","javascript"} do
|
||||
dap.configurations[language]={
|
||||
{
|
||||
type="pwa-node",
|
||||
request="launch",
|
||||
name="Launch file",
|
||||
program="${file}",
|
||||
cwd="${workspaceFolder}",
|
||||
runtimeExecutable="node",
|
||||
},
|
||||
}
|
||||
end
|
||||
```
|
||||
We need to add ui for debugger too so add this as entry in `plugins.lua`
|
||||
```lua
|
||||
{
|
||||
|
||||
"rcarriga/nvim-dap-ui",
|
||||
event="VeryLazy",
|
||||
dependencies = "mfussenegger/nvim-dap",
|
||||
config=function ()
|
||||
local dap=require("dap")
|
||||
local dapui=require("dapui")
|
||||
require("dapui").setup()
|
||||
dap.listeners.after.event_initialized["dapui_config"] = function ()
|
||||
dapui.open()
|
||||
end
|
||||
dap.listeners.before.event_terminated["dapui_config"]=function ()
|
||||
dapui.close()
|
||||
end
|
||||
dap.listeners.before.event_exited["dapui_config"]=function ()
|
||||
dapui.close()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
},
|
||||
```
|
||||
|
||||
Custom mappings for debugger
|
||||
Create `~/.config/nvim/lua/custom/mappings.lua` and open it and type.
|
||||
```lua
|
||||
local M = {}
|
||||
|
||||
M.dap={
|
||||
plugin=true,
|
||||
n = {
|
||||
["<leader>db"]={
|
||||
"<cmd> DapToggleBreakpoint <CR>",
|
||||
"Add breakpoint at line"
|
||||
},
|
||||
["<leader>dr"]= {
|
||||
"<cmd> DapContinue <CR>",
|
||||
"Run or continue the debugger"
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
return M
|
||||
```
|
||||
Now add this in nvim-dap entry like this in `plugins.lua`
|
||||
```lua
|
||||
{
|
||||
"mfussenegger/nvim-dap",
|
||||
config=function ()
|
||||
require "custom.configs.dap"
|
||||
require("core.utils").load_mappings("dap")
|
||||
end
|
||||
},
|
||||
```
|
||||
Finally in `chadrc.lua` add the mappings file too
|
||||
```lua
|
||||
|
||||
local M = {}
|
||||
|
||||
M.ui = { theme = 'oceanic-next' }
|
||||
M.plugins="custom.plugins"
|
||||
M.mappings=require "custom.mappings"
|
||||
|
||||
return M
|
||||
```
|
||||
|
||||
- Using debugger
|
||||
space and `db` to toggle breakpoint.
|
||||
To run debugger space and `dr`.
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
Configuring c++ on neovim
|
||||
https://www.youtube.com/watch?v=lsFoZIg-oDs
|
||||
|
||||
- Installing clangd(LSP)
|
||||
In ensure_installed section then type `:MasonInstallAll`.
|
||||
In lspconfig.lua add this
|
||||
```lua
|
||||
lspconfig.clangd.setup{
|
||||
on_attach=on_attach,
|
||||
capabilities=capabilities,
|
||||
init_options={
|
||||
preferences={
|
||||
disableSuggestions=true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
Add instead this in `lspconfig.lua` to remove warning
|
||||
```lua
|
||||
local cmp_nvim_lsp = require "cmp_nvim_lsp"
|
||||
|
||||
require("lspconfig").clangd.setup {
|
||||
on_attach = on_attach,
|
||||
capabilities = cmp_nvim_lsp.default_capabilities(),
|
||||
cmd = {
|
||||
"clangd",
|
||||
"--offset-encoding=utf-16",
|
||||
},
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- Autoformatter
|
||||
Install clang-format. Add following in `plugins.lua`
|
||||
```lua
|
||||
{
|
||||
"jose-elias-alvarez/null-ls.nvim",
|
||||
event="VeryLazy",
|
||||
opts=function ()
|
||||
return require "custom.configs.null-ls"
|
||||
end,
|
||||
},
|
||||
|
||||
```
|
||||
Create `~/.config/nvim/lua/custom/configs/null-ls.lua`
|
||||
and type this
|
||||
```lua
|
||||
local null_ls= require("null-ls")
|
||||
|
||||
local opts={
|
||||
sources={
|
||||
null_ls.builtins.formatting.clang_format,
|
||||
}
|
||||
}
|
||||
|
||||
return opts
|
||||
```
|
||||
Press space and type `fm` to format it
|
||||
To have a custom file formatting we need to have `.clang-format` in out project folder. Generate using this
|
||||
`~/.local/share/nvim/mason/bin/clang-format --style GNU --dump-config > .clang-format`
|
||||
|
||||
- Setup autoformat on save
|
||||
In `null-ls.lua` file
|
||||
modify it like this
|
||||
```lua
|
||||
local augroup=vim.api.nvim_create_augroup("LspFormatting",{})
|
||||
local null_ls= require("null-ls")
|
||||
|
||||
local opts={
|
||||
sources={
|
||||
null_ls.builtins.formatting.clang_format,
|
||||
},
|
||||
on_attach=function (client,bufnr)
|
||||
if client.supports_method("textDocument/formatting") then
|
||||
vim.api.nvim_clear_autocmds({
|
||||
group=augroup,
|
||||
buffer=bufnr,
|
||||
})
|
||||
vim.api.nvim_create_autocmd("BufWritePre",{
|
||||
group=augroup,
|
||||
buffer=bufnr,
|
||||
callback=function ()
|
||||
vim.lsp.buf.format({bufnr=bufnr})
|
||||
end,
|
||||
})
|
||||
end
|
||||
end,
|
||||
}
|
||||
|
||||
return opts
|
||||
```
|
||||
|
||||
- Debugger
|
||||
With mason, install `codelldb` plugin too.
|
||||
To able to debug them use `--debug` flag after gcc command when compiling like this
|
||||
`gcc --debug main.cpp -o main`
|
||||
And when running debugger mention name of executable file ie `main` here
|
||||
In `plugins.lua` add this
|
||||
```lua
|
||||
{
|
||||
"mfussenegger/nvim-dap",
|
||||
config=function (_, _)
|
||||
require("core.utils").load_mappings("dap")
|
||||
end
|
||||
},
|
||||
-- Also add this
|
||||
{
|
||||
"jay-babu/mason-nvim-dap.nvim",
|
||||
event="VeryLazy",
|
||||
dependencies={
|
||||
"williamboman/mason.nvim",
|
||||
"mfussenegger/nvim-dap",
|
||||
},
|
||||
opts={
|
||||
handlers={}
|
||||
},
|
||||
},
|
||||
-- Add nvim-dap-ui too from javascript debugger too
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
Also changes in `chadrc.lua` and add `mappings.lua` like with js debugger too
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
Configuring neovim
|
||||
|
||||
https://www.youtube.com/watch?v=stqUbv-5u2s
|
||||
https://github.com/nvim-lua/kickstart.nvim/blob/master/init.lua
|
||||
|
||||
- Copy init.lua from the github link to `~/.config/nvim/init.lua`
|
||||
- Next time when nvim is started all plugins definied in this will be loaded
|
||||
- Press space then type `sf` to switch through files
|
||||
- Type `:Telescope keymaps` to get some new keymaps feature
|
||||
- Type `:Mason` to install language servers for autocompletions
|
||||
|
||||
Plugins
|
||||
- Install vim plug
|
||||
```
|
||||
sh -c 'curl -fLo "${XDG_DATA_HOME:-$HOME/.local/share}"/nvim/site/autoload/plug.vim --create-dirs \
|
||||
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim'
|
||||
```
|
||||
|
||||
- Configure vim-plug
|
||||
To install plugins like coc.nvim
|
||||
type following in `init.vim` or `vimrc.vim`
|
||||
```text
|
||||
call plug#begin()
|
||||
Plug 'neoclide/coc.nvim', {'branch': 'release'}
|
||||
call plug#end()
|
||||
|
||||
```
|
||||
|
||||
As init.lua is already there so init.vim cant be there so change its name to `vimrc.vim` and include it in `init.lua` like this
|
||||
```lua
|
||||
local vimrc = vim.fn.stdpath("config") .. "/vimrc.vim"
|
||||
vim.cmd.source(vimrc)
|
||||
```
|
||||
|
||||
- PlugInstall
|
||||
Then in neovim type `:PlugInstall` to install plugin listed in `vimrc.vim` file.
|
||||
and remaining extensions like this
|
||||
`:CocInstall coc-json coc-tsserver`
|
||||
|
||||
9
joplin notion extension/Web Development/Neovim/Extras.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
Extras
|
||||
|
||||
- Multi cursor typing in neovim
|
||||
https://stackoverflow.com/questions/12399572/vim-how-to-insert-in-visual-block-mode
|
||||
Try this
|
||||
After selecting a block of text, press Shift+i or capital I.
|
||||
Lowercase i will not work.
|
||||
Then type the things you want and finally to apply it to all lines, press Esc twice.
|
||||
|
||||
6
joplin notion extension/Web Development/Python/Extras.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
Extras
|
||||
|
||||
python http server
|
||||
`python -m http.server 8000`
|
||||
for custom directory
|
||||
`python -m http.server 8000 --directory /path/to/your/folder`
|
||||
43
joplin notion extension/Web Development/Python/Flet/Intro.md
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
Intro
|
||||
https://flet.dev/docs/
|
||||
Flutter in python
|
||||
|
||||
- Installation
|
||||
`pip install flet` (Need python version>3.8)
|
||||
- Running code
|
||||
`python counter.py`
|
||||
- Sample code
|
||||
```py
|
||||
import flet as ft
|
||||
|
||||
def main(page: ft.Page):
|
||||
page.title = "Flet counter example"
|
||||
page.vertical_alignment = ft.MainAxisAlignment.CENTER
|
||||
|
||||
txt_number = ft.TextField(value="0", text_align=ft.TextAlign.RIGHT, width=100)
|
||||
|
||||
def minus_click(e):
|
||||
txt_number.value = str(int(txt_number.value) - 1)
|
||||
page.update()
|
||||
|
||||
def plus_click(e):
|
||||
txt_number.value = str(int(txt_number.value) + 1)
|
||||
page.update()
|
||||
|
||||
page.add(
|
||||
ft.Row(
|
||||
[
|
||||
ft.IconButton(ft.icons.REMOVE, on_click=minus_click),
|
||||
txt_number,
|
||||
ft.IconButton(ft.icons.ADD, on_click=plus_click),
|
||||
],
|
||||
alignment=ft.MainAxisAlignment.CENTER,
|
||||
)
|
||||
)
|
||||
|
||||
ft.app(target=main)
|
||||
```
|
||||
- Packing
|
||||
Need to install pyinstaller first using `pip install pyinstaller`
|
||||
then
|
||||
`flet pack counter.py`
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
Installing modules
|
||||
|
||||
|
||||
- When installing modules with pip we may get this error
|
||||
`This environment is externally managed`
|
||||
So use this to bypass the error message
|
||||
`pip install package_name --break-system-packages`
|
||||
- another error may be `Expat >=2.6.0 API function XML_SetReparseDeferralEnabled`
|
||||
in this case upgrade `expat` package
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
Tkinter Snippets
|
||||
|
||||
|
||||
[10 Interesting Python Tkinter Programs with Code _ by Swathi Arun _ Level Up Coding (12_11_2023 3_47_59 am).html](../../../_resources/10%20Interesting%20Python%20Tkinter%20Programs%20with%20Code%20_.html)
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
compiling python
|
||||
|
||||
1. download tar file from python site.
|
||||
2. after extracting and moving to this directory, run `make -j $(nproc)` to use all cpu cores or just use `make`
|
||||
3. then run `sudo make altinstall` to have packages on `/usr/local/bin` or use `make DESTDIR=~/local install` (this might not always work)
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package
|
||||
|
||||
- to install in virtual environment
|
||||
- `python3 -m venv env` : to create venv
|
||||
- `source env/bin/activate` : to activate it
|
||||
- `pip install -r requirements.txt`
|
||||
- finally to deactivate use `deactivate`
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
pyenv
|
||||
https://realpython.com/intro-to-pyenv/
|
||||
|
||||
- Installation
|
||||
`$ curl https://pyenv.run | bash`
|
||||
- Confirguration
|
||||
Adding following in `~/.bashrc`
|
||||
```
|
||||
export PATH="$HOME/.pyenv/bin:$PATH"
|
||||
eval "$(pyenv init -)"
|
||||
eval "$(pyenv virtualenv-init -)"
|
||||
```
|
||||
|
||||
- Use
|
||||
`$ pyenv install --list | grep " 3\.[678]"`
|
||||
To install desired one
|
||||
`pyenv install -v 3.7.2`
|
||||
List versions
|
||||
`pyenv versions`
|
||||
- Switching versions
|
||||
`pyenv global 2.7.15`
|
||||
|
||||
14
joplin notion extension/Web Development/React/Basics.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
Basics
|
||||
|
||||
```js
|
||||
const [name, setName] = useState('Edward');
|
||||
const [age, setAge] = useState('0');
|
||||
|
||||
|
||||
function handleClick() {
|
||||
setName('Taylor');
|
||||
setAge(a => a + 1);
|
||||
}
|
||||
```
|
||||
|
||||
as react batches states updates so it when it is called multiple times it may not update correctly so this updater function/functional form helps
|
||||
2
joplin notion extension/Web Development/React/Issues.md
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
Issues
|
||||
- Sometimes there may be a problem by adding keys in component, so make sure to not use any state as in from useState hook or any state as in instance as key
|
||||
3
joplin notion extension/Web Development/React/Links.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
Links
|
||||
|
||||
- https://morioh.com/a/8a60baf74ebe/dockerizing-a-react-application-with-nodejs-postgres-and-nginx
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
Intro
|
||||
https://github.com/nodegui/react-nodegui
|
||||
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
Packer
|
||||
https://github.com/nodegui/packer
|
||||
|
||||
To create executable file
|
||||
|
||||
- First step is to install the packer as a dev dependency. You can do so by:
|
||||
|
||||
`npm install --save-dev @nodegui/packer`
|
||||
|
||||
- Next you can run the init command:
|
||||
|
||||
`npx nodegui-packer --init MyApp`
|
||||
This will produce the deploy directory containing the template. You can modify this to suite your needs. Like add icons, change the name, description and add other native features or dependencies. Make sure you commit this directory.
|
||||
|
||||
- Next you can run the pack command:
|
||||
|
||||
`npx nodegui-packer --pack <path to dist>`
|
||||
This command essential takes the dist folder as the input and puts it in the suitable location inside the standalone executable. Also it runs the correct deployment tool (macdeployqt incase of mac, etc) and packs in the dependencies. The output of the command is found under the build directory. You should gitignore the build directory.
|
||||
|
||||
123
joplin notion extension/Web Development/React/Redux.md
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
Redux
|
||||
|
||||
|
||||
Sure, Redux is commonly used to manage state in complex React applications, avoiding the need to pass props deeply through nested components. Below is a simple example that illustrates how Redux can be used to share state between components without prop drilling.
|
||||
|
||||
Let's create a counter app where you can increase, decrease, and reset the count. We'll use three components: `App` (the parent component), `CounterDisplay` (to display the count), and `CounterControls` (to increase, decrease, or reset the count), showing how Redux allows them to communicate without passing props through each other directly.
|
||||
|
||||
### Step 1: Setup
|
||||
|
||||
First, ensure you have Redux and React-Redux installed in your project:
|
||||
|
||||
```bash
|
||||
npm install redux react-redux
|
||||
```
|
||||
|
||||
### Step 2: Create Redux Store, Reducer, and Actions
|
||||
|
||||
**store.js**
|
||||
```javascript
|
||||
import { createStore } from 'redux';
|
||||
|
||||
// Reducer function
|
||||
function counterReducer(state = { count: 0 }, action) {
|
||||
switch (action.type) {
|
||||
case 'INCREMENT':
|
||||
return { count: state.count + 1 };
|
||||
case 'DECREMENT':
|
||||
return { count: state.count - 1 };
|
||||
case 'RESET':
|
||||
return { count: 0 };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
// Create and export the store
|
||||
export const store = createStore(counterReducer);
|
||||
```
|
||||
|
||||
### Step 3: Setup Redux Provider
|
||||
|
||||
In your main entry file (like `index.js`), wrap your root component with the `Provider` from `react-redux` and pass the store to it:
|
||||
|
||||
**index.js**
|
||||
```javascript
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import App from './App';
|
||||
import { Provider } from 'react-redux';
|
||||
import { store } from './store';
|
||||
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<App />
|
||||
</Provider>,
|
||||
document.getElementById('root')
|
||||
);
|
||||
```
|
||||
|
||||
### Step 4: Creating Components
|
||||
|
||||
**App.js** - The parent component
|
||||
```javascript
|
||||
import React from 'react';
|
||||
import CounterDisplay from './CounterDisplay';
|
||||
import CounterControls from './CounterControls';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Redux Counter Example</h1>
|
||||
<CounterDisplay />
|
||||
<CounterControls />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
**CounterDisplay.js** - Component to display the count
|
||||
```javascript
|
||||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
function CounterDisplay() {
|
||||
const count = useSelector(state => state.count); // Accessing count from Redux state
|
||||
return <h2>Count: {count}</h2>;
|
||||
}
|
||||
|
||||
export default CounterDisplay;
|
||||
```
|
||||
|
||||
**CounterControls.js** - Component to control the count
|
||||
```javascript
|
||||
import React from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
|
||||
function CounterControls() {
|
||||
const dispatch = useDispatch(); // To dispatch actions
|
||||
return (
|
||||
<div>
|
||||
<button onClick={() => dispatch({ type: 'INCREMENT' })}>Increase</button>
|
||||
<button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrease</button>
|
||||
<button onClick={() => dispatch({ type: 'RESET' })}>Reset</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default CounterControls;
|
||||
```
|
||||
|
||||
### Brief Explanation
|
||||
|
||||
In this example:
|
||||
|
||||
- We've created a Redux store to hold our state, which in this case is simply a `count` value.
|
||||
- The `counterReducer` handles actions (increment, decrement, reset) to update the state accordingly.
|
||||
- The `App` component is our root component, rendering both the `CounterDisplay` and `CounterControls` components.
|
||||
- The `CounterDisplay` component uses `useSelector` to read the `count` value from the Redux store directly, without needing to receive it as a prop.
|
||||
- The `CounterControls` component uses `useDispatch` to dispatch actions that update the state, without needing to receive dispatch functions as props.
|
||||
|
||||
By using Redux, we've avoided the need to pass the `count` state or the dispatch functions through the `App` component, directly connecting the `CounterDisplay` and `CounterControls` components to the state they need. This simplifies the component structure and makes state management more efficient and scalable for larger applications.
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
Resources
|
||||
|
||||
- https://primereact.org/ : template for react components
|
||||
primereact-10.2.1.tgz https://shdw-drive.genesysgo.net/C7yTh47Yqy2zbUbbA9QfAm59XBAqX5VU1QWU9Uyiex9Q/c44da329-b917-4fdf-9e9e-128d74a15154.tgz
|
||||
|
||||
- https://mui.com/material-ui/ :template for react components
|
||||
- https://navithecoderboi.me/#skills : portfolio source code
|
||||
- react-icons : to replace font-awesome cdn thing
|
||||
|
|
@ -0,0 +1,384 @@
|
|||
Drag and Drop File Upload
|
||||
|
||||
|
||||
|
||||
[react-drop-file-input-main.zip](../../../../_resources/react-drop-file-input-main.zip)
|
||||
|
||||
|
||||
- JSX
|
||||
|
||||
```JSX
|
||||
import React, { useRef, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import './drop-file-input.css';
|
||||
|
||||
import { ImageConfig } from '../../config/ImageConfig';
|
||||
import uploadImg from '../../assets/cloud-upload-regular-240.png';
|
||||
|
||||
const DropFileInput = props => {
|
||||
|
||||
const wrapperRef = useRef(null);
|
||||
|
||||
const [fileList, setFileList] = useState([]);
|
||||
|
||||
const onDragEnter = () => wrapperRef.current.classList.add('dragover');
|
||||
|
||||
const onDragLeave = () => wrapperRef.current.classList.remove('dragover');
|
||||
|
||||
const onDrop = () => wrapperRef.current.classList.remove('dragover');
|
||||
|
||||
const onFileDrop = (e) => {
|
||||
const newFile = e.target.files[0];
|
||||
if (newFile) {
|
||||
const updatedList = [...fileList, newFile];
|
||||
setFileList(updatedList);
|
||||
props.onFileChange(updatedList);
|
||||
}
|
||||
}
|
||||
|
||||
const fileRemove = (file) => {
|
||||
const updatedList = [...fileList];
|
||||
updatedList.splice(fileList.indexOf(file), 1);
|
||||
setFileList(updatedList);
|
||||
props.onFileChange(updatedList);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
ref={wrapperRef}
|
||||
className="drop-file-input"
|
||||
onDragEnter={onDragEnter}
|
||||
onDragLeave={onDragLeave}
|
||||
onDrop={onDrop}
|
||||
>
|
||||
<div className="drop-file-input__label">
|
||||
<img src={uploadImg} alt="" />
|
||||
<p>Drag & Drop your files here</p>
|
||||
</div>
|
||||
<input type="file" value="" onChange={onFileDrop}/>
|
||||
</div>
|
||||
{
|
||||
fileList.length > 0 ? (
|
||||
<div className="drop-file-preview">
|
||||
<p className="drop-file-preview__title">
|
||||
Ready to upload
|
||||
</p>
|
||||
{
|
||||
fileList.map((item, index) => (
|
||||
<div key={index} className="drop-file-preview__item">
|
||||
<img src={ImageConfig[item.type.split('/')[1]] || ImageConfig['default']} alt="" />
|
||||
<div className="drop-file-preview__item__info">
|
||||
<p>{item.name}</p>
|
||||
<p>{item.size}B</p>
|
||||
</div>
|
||||
<span className="drop-file-preview__item__del" onClick={() => fileRemove(item)}>x</span>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
) : null
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
DropFileInput.propTypes = {
|
||||
onFileChange: PropTypes.func
|
||||
}
|
||||
|
||||
export default DropFileInput;
|
||||
```
|
||||
|
||||
|
||||
CSS
|
||||
|
||||
```css
|
||||
.drop-file-input {
|
||||
position: relative;
|
||||
width: 400px;
|
||||
height: 200px;
|
||||
border: 2px dashed var(--border-color);
|
||||
border-radius: 20px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
background-color: var(--input-bg);
|
||||
}
|
||||
|
||||
.drop-file-input input {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.drop-file-input:hover,
|
||||
.drop-file-input.dragover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.drop-file-input__label {
|
||||
text-align: center;
|
||||
color: var(--txt-second-color);
|
||||
font-weight: 600;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.drop-file-input__label img {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.drop-file-preview {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
.drop-file-preview p {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.drop-file-preview__title {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.drop-file-preview__item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
margin-bottom: 10px;
|
||||
background-color: var(--input-bg);
|
||||
padding: 15px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.drop-file-preview__item img {
|
||||
width: 50px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.drop-file-preview__item__info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.drop-file-preview__item__del {
|
||||
background-color: var(--box-bg);
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
box-shadow: var(--box-shadow);
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.drop-file-preview__item:hover .drop-file-preview__item__del {
|
||||
opacity: 1;
|
||||
}
|
||||
```
|
||||
---
|
||||
|
||||
- For multiple file uploading use this and to limit the height of preview file list:
|
||||
```jsx
|
||||
import React, { useRef, useState } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import "./drop-file-input.css";
|
||||
|
||||
import { ImageConfig } from "../../config/ImageConfig";
|
||||
import uploadImg from "../../assets/cloud-upload-regular-240.png";
|
||||
|
||||
const DropFileInput = (props) => {
|
||||
const wrapperRef = useRef(null);
|
||||
|
||||
const [fileList, setFileList] = useState([]);
|
||||
|
||||
const onDragEnter = () => wrapperRef.current.classList.add("dragover");
|
||||
|
||||
const onDragLeave = () => wrapperRef.current.classList.remove("dragover");
|
||||
|
||||
const onDrop = () => wrapperRef.current.classList.remove("dragover");
|
||||
|
||||
const onFileDrop = (e) => {
|
||||
const newFiles = e.target.files;
|
||||
if (newFiles.length !== 0) {
|
||||
const updatedList = [...fileList, ...newFiles];
|
||||
setFileList(updatedList);
|
||||
props.onFileChange(updatedList);
|
||||
}
|
||||
};
|
||||
|
||||
const fileRemove = (file) => {
|
||||
const updatedList = [...fileList];
|
||||
updatedList.splice(fileList.indexOf(file), 1);
|
||||
setFileList(updatedList);
|
||||
props.onFileChange(updatedList);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
ref={wrapperRef}
|
||||
className="drop-file-input"
|
||||
onDragEnter={onDragEnter}
|
||||
onDragLeave={onDragLeave}
|
||||
onDrop={onDrop}
|
||||
>
|
||||
<div className="drop-file-input__label">
|
||||
<img src={uploadImg} alt="" />
|
||||
<p>Drag & Drop your files here</p>
|
||||
</div>
|
||||
<input type="file" value="" multiple onChange={onFileDrop} />
|
||||
</div>
|
||||
{fileList.length > 0 ? (
|
||||
<div className="drop-file-preview">
|
||||
<p className="drop-file-preview__title">Ready to upload</p>
|
||||
{fileList.map((item, index) => (
|
||||
<div key={index} className="drop-file-preview__item">
|
||||
<img
|
||||
src={
|
||||
ImageConfig[item.type.split("/")[1]] || ImageConfig["default"]
|
||||
}
|
||||
alt=""
|
||||
/>
|
||||
<div className="drop-file-preview__item__info">
|
||||
<p>{item.name}</p>
|
||||
<p>{item.size}B</p>
|
||||
</div>
|
||||
<span
|
||||
className="drop-file-preview__item__del"
|
||||
onClick={() => fileRemove(item)}
|
||||
>
|
||||
x
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
DropFileInput.propTypes = {
|
||||
onFileChange: PropTypes.func,
|
||||
};
|
||||
|
||||
export default DropFileInput;
|
||||
|
||||
```
|
||||
|
||||
|
||||
CSS
|
||||
```css
|
||||
.drop-file-input {
|
||||
position: relative;
|
||||
width: 400px;
|
||||
height: 200px;
|
||||
border: 2px dashed var(--border-color);
|
||||
border-radius: 20px;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
background-color: var(--input-bg);
|
||||
}
|
||||
|
||||
.drop-file-input input {
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.drop-file-input:hover,
|
||||
.drop-file-input.dragover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.drop-file-input__label {
|
||||
text-align: center;
|
||||
color: var(--txt-second-color);
|
||||
font-weight: 600;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.drop-file-input__label img {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.drop-file-preview {
|
||||
margin-top: 30px;
|
||||
max-height: 70%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.drop-file-preview p {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.drop-file-preview__title {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.drop-file-preview__item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
margin-bottom: 10px;
|
||||
background-color: var(--input-bg);
|
||||
padding: 15px;
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.drop-file-preview__item img {
|
||||
width: 50px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.drop-file-preview__item__info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.drop-file-preview__item__del {
|
||||
background-color: var(--box-bg);
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
box-shadow: var(--box-shadow);
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.drop-file-preview__item:hover .drop-file-preview__item__del {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
Toast
|
||||
|
||||
|
||||
|
||||
https://primereact.org/toast/
|
||||
|
||||
Here package `primereact` is used so use `npm i primereact` to install it
|
||||
|
||||
In Toast.jsx
|
||||
```jsx
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
import { Toast } from "primereact/toast";
|
||||
// import { Button } from "primereact/button";
|
||||
|
||||
const ToastEle = (props) => {
|
||||
const toast = useRef(null);
|
||||
|
||||
const { errorMessage, errorVisibility, setErrorVisibility } = props;
|
||||
|
||||
const showError = () => {
|
||||
toast.current.show({ severity: "error", detail: errorMessage, life: 3000 });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (errorVisibility === true) {
|
||||
showError();
|
||||
setErrorVisibility(false);
|
||||
}
|
||||
}, [errorVisibility]);
|
||||
|
||||
return <Toast ref={toast} position="top-left" />;
|
||||
};
|
||||
|
||||
export default ToastEle;
|
||||
```
|
||||
|
||||
In App.jsx
|
||||
|
||||
```jsx
|
||||
import { PrimeReactProvider } from "primereact/api";
|
||||
import "primereact/resources/themes/lara-light-indigo/theme.css"; // theme
|
||||
// import "primeflex/primeflex.css"; // css utility
|
||||
// import "primeicons/primeicons.css";
|
||||
import "primereact/resources/primereact.css"; //
|
||||
import ToastEle from "./Components/Toast";
|
||||
|
||||
|
||||
function App() {
|
||||
|
||||
|
||||
// for error message at top
|
||||
const [errorVisibility, setErrorVisibility] = useState(false);
|
||||
const [errorMessage, setErrorMessage] = useState("");
|
||||
|
||||
return(
|
||||
<PrimeReactProvider>
|
||||
<ToastEle
|
||||
errorVisibility={errorVisibility}
|
||||
errorMessage={errorMessage}
|
||||
setErrorVisibility={setErrorVisibility}
|
||||
/>
|
||||
</PrimeReactProvider>
|
||||
)
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
Initialization
|
||||
|
||||
- For React :
|
||||
https://tailwindcss.com/docs/guides/create-react-app
|
||||
- `npm i -D tailwindcss` or `npm i tailwindcss -save-dev`
|
||||
- `npx tailwindcss init`to create `tailwind.config.js`
|
||||
- Configure `tailwind.config.js`
|
||||
```js
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
"./src/**/*.{js,jsx,ts,tsx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
```
|
||||
- Add the `@tailwind` directives for each of Tailwind’s layers to your `./src/index.css` file.
|
||||
```css
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
```
|
||||
- Start your build process `npm run start`
|
||||
- For Nextjs
|
||||
https://tailwindcss.com/docs/guides/nextjs
|
||||
- `npm install -D tailwindcss postcss autoprefixer`
|
||||
- `npx tailwindcss init -p` to generate `tailwind.config.js` and `postcss.config.js`
|
||||
- Configuring `tailwind.config.js`
|
||||
```js
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
"./app/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./components/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
|
||||
// Or if using `src` directory:
|
||||
"./src/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
```
|
||||
- rest all same as react. instead of `index.css`, use `globals.css` for nextjs
|
||||
|
||||
### vanilla
|
||||
https://v3.tailwindcss.com/docs/installation
|
||||
|
||||
```sh
|
||||
npm install -D tailwindcss@3
|
||||
npx tailwindcss init
|
||||
```
|
||||
|
||||
in src/input.css
|
||||
```css
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
```
|
||||
|
||||
and finally(for vanilla cases atleast)
|
||||
`npx tailwindcss -i ./src/input.css -o ./src/output.css --watch`
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
Change parameters of URL without refreshing it
|
||||
|
||||
```jsx
|
||||
const changeURLParams = (newValue) => {
|
||||
const newURL = `${window.location.pathname}${newValue}`;
|
||||
|
||||
window.history.pushState({ path: newURL }, "", newURL);
|
||||
};
|
||||
```
|
||||
|
||||
Change queries of URL without refreshing it
|
||||
|
||||
```jsx
|
||||
const changeQueryParams = () => {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
urlParams.set('queryParamName', 'newValue');
|
||||
|
||||
const newURL = `${window.location.pathname}?${urlParams.toString()}`;
|
||||
|
||||
window.history.pushState({ path: newURL }, '', newURL);
|
||||
};
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
Props.children
|
||||
|
||||
|
||||
|
||||
My simple explanation of what this.props.children does is that it is used to display whatever you include between the opening and closing tags when invoking a component.
|
||||
|
||||
A simple example:
|
||||
|
||||
Here’s an example of a stateless function that is used to create a component. Again, since this is a function, there is no this keyword so just use props.children
|
||||
```jsx
|
||||
const Picture = (props) => {
|
||||
return (
|
||||
<div>
|
||||
<img src={props.src}/>
|
||||
{props.children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
This component contains an <img> that is receiving some props and then it is displaying {props.children}.
|
||||
|
||||
Whenever this component is invoked, {props.children} will also be displayed and this is just a reference to what is between the opening and closing tags of the component.
|
||||
|
||||
```jsx
|
||||
//App.js
|
||||
render () {
|
||||
return (
|
||||
<div className='container'>
|
||||
<Picture key={picture.id} src={picture.src}>
|
||||
//what is placed here is passed as props.children
|
||||
</Picture>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
Instead of invoking the component with a self-closing tag <Picture /> if you invoke it with full opening and closing tags <Picture> </Picture> you can then place more code between it.
|
||||
|
||||
This de-couples the <Picture> component from its content and makes it more reusable.
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
ternary operator for routing
|
||||
|
||||
When using `{}` for js expression make sure to wrap in under any component or element whether it is empty like `<> </>`
|
||||
|
||||
```jsx
|
||||
|
||||
const [route,setRoute]=useState('home')
|
||||
return (
|
||||
<>
|
||||
{route === "home" ? (
|
||||
<div className="App">
|
||||
<Nav />
|
||||
<Article
|
||||
files={files}
|
||||
setFiles={setFiles}
|
||||
category={category}
|
||||
setCategory={setCategory}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<Output />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
```
|
||||
161
joplin notion extension/Web Development/React/electron.md
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
electron
|
||||
https://www.electronjs.org/docs/latest/tutorial/tutorial-first-app
|
||||
|
||||
- Make a folder and open terminal and when in project directory execute this
|
||||
`npm init`
|
||||
- Now create a file `main.js` and print something like `hello world`
|
||||
```js
|
||||
console.log('hello world')
|
||||
```
|
||||
- Now to make `main.js` entry point. have this following configuration in `package.json`. main property have to point to main.js and start script have to be `electron .`
|
||||
```json
|
||||
{
|
||||
"name": "electron-app",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"start": "electron ."
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"electron": "^33.2.0"
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
- Start app with `npm run start`. this will output hello world. no window will open as its only cli
|
||||
|
||||
|
||||
**GUI**
|
||||
- to serve html file `index.html`
|
||||
```html
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
|
||||
<meta
|
||||
http-equiv="Content-Security-Policy"
|
||||
content="default-src 'self'; script-src 'self'"
|
||||
/>
|
||||
<meta
|
||||
http-equiv="X-Content-Security-Policy"
|
||||
content="default-src 'self'; script-src 'self'"
|
||||
/>
|
||||
<title>Hello from Electron renderer!</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello from Electron renderer!</h1>
|
||||
<p>👋</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
```
|
||||
|
||||
- in main.js
|
||||
```js
|
||||
const { app, BrowserWindow } = require("electron");
|
||||
|
||||
const createWindow = () => {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
title: "SilverBullet",
|
||||
autoHideMenuBar: true,
|
||||
|
||||
icon: "images/silverbullet.jpg",
|
||||
});
|
||||
|
||||
// win.loadFile("index.html");
|
||||
win.loadURL("http://localhost:3001");
|
||||
};
|
||||
|
||||
app.whenReady().then(() => {
|
||||
createWindow();
|
||||
});
|
||||
|
||||
app.on("window-all-closed", function () {
|
||||
if (process.platform !== "darwin") {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
```
|
||||
|
||||
c
|
||||
**Packaging electron app**
|
||||
https://www.electronjs.org/docs/latest/tutorial/tutorial-packaging
|
||||
- run following
|
||||
```bash
|
||||
npm install --save-dev @electron-forge/cli
|
||||
npx electron-forge import
|
||||
```
|
||||
- then in package.json, following scripts will be added
|
||||
```json
|
||||
//...
|
||||
"scripts": {
|
||||
"start": "electron-forge start",
|
||||
"package": "electron-forge package",
|
||||
"make": "electron-forge make"
|
||||
},
|
||||
//...
|
||||
```
|
||||
- to package use `npm run package`
|
||||
|
||||
|
||||
**Context menu**
|
||||
https://stackoverflow.com/questions/71698892/how-to-apply-electron-context-menu-in-window
|
||||
|
||||
|
||||
**Open file in default app instead of new window**
|
||||
- In electron if there are assets or files and we wanna open then we have to use shell object
|
||||
and web-contents setWindowOpenHandler to intercept opening of new window to intercept them and direct it to default file opener
|
||||
https://www.electronjs.org/docs/latest/api/web-contents#contentssetwindowopenhandlerhandler
|
||||
```js
|
||||
const createWindow = () => {
|
||||
const win = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
title: "SilverBullet",
|
||||
autoHideMenuBar: true,
|
||||
|
||||
icon: "images/silverbullet.jpg",
|
||||
});
|
||||
|
||||
// win.title = "Silverbullet";
|
||||
|
||||
// win.loadFile("index.html");
|
||||
win.loadURL(`http://${hostname}:${PORT}`);
|
||||
|
||||
|
||||
|
||||
win.webContents.setWindowOpenHandler((details) => {
|
||||
console.log("detected");
|
||||
// shell.openExternal(url); // open link in default app
|
||||
// console.log(__dirname, url);
|
||||
// shell.openPath(path.join(__dirname, ur));
|
||||
// shell.openPath(winDetails.url);
|
||||
|
||||
// const urlString = decodeURI(winDetails.url).replace(
|
||||
// `http://${hostname}:${PORT}/`,
|
||||
// "file://",
|
||||
// );
|
||||
const urlString = details.url.replace(
|
||||
`http://${hostname}:${PORT}/`,
|
||||
`file://${datadirname}/`,
|
||||
// "",
|
||||
);
|
||||
|
||||
console.log(urlString);
|
||||
shell.openExternal(urlString);
|
||||
|
||||
return null;
|
||||
});
|
||||
};
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
Advanced
|
||||
|
||||
- server actions
|
||||
able to use forms in server component
|
||||
https://inv.in.projectsegfau.lt/watch?v=Yc2MJYwLqzs
|
||||
- sending form data
|
||||
https://nextjs.org/docs/pages/building-your-application/data-fetching/forms-and-mutations
|
||||
https://www.youtube.com/watch?v=AbLAxs-7yl0
|
||||
for `application/x-www-form-urlencoded`
|
||||
just use
|
||||
```jsx
|
||||
<form action="/route/api" method="POST">
|
||||
<input type="text" name="city">
|
||||
</form>
|
||||
|
||||
const onSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const formData = new FormData(e.currentTarget);
|
||||
|
||||
const response = await fetch("/addschool/api", {
|
||||
method: "POST",
|
||||
body: formData,
|
||||
});
|
||||
};
|
||||
|
||||
```
|
||||
this will just Formdata which is not multipart but of urlencoded and field will be `city`
|
||||
|
||||
for multipart form data
|
||||
|
||||
```html
|
||||
<form onSubmit={onSubmit}>
|
||||
<input type="text" name="city">
|
||||
</form>
|
||||
```
|
||||
|
||||
- receiving form data
|
||||
```js
|
||||
import { redirect } from "next/navigation";
|
||||
import fs from "fs";
|
||||
|
||||
export async function POST(request) {
|
||||
// console.log("request: ", request.body);
|
||||
|
||||
const formData = await request.formData();
|
||||
|
||||
console.log(formData);
|
||||
|
||||
const number = formData.get("contactNumber");
|
||||
|
||||
const file = formData.get("imageAttachment");
|
||||
|
||||
const fileBuffer = Buffer.from(await file.arrayBuffer());
|
||||
|
||||
console.log("fileBuffer: ", fileBuffer);
|
||||
|
||||
fs.writeFileSync(file.name, fileBuffer);
|
||||
|
||||
console.log("number ", number);
|
||||
|
||||
redirect("/addschool");
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
- uploading file in vercel blob
|
||||
https://vercel.com/brads-projects-55888f01/~/stores/blob/store_I4WjQqMnSOkFDxWt/guides
|
||||
- standalone builds
|
||||
node modules may contain lot of modules that are not required so
|
||||
1. configure next.config.js like this
|
||||
```js
|
||||
module.exports={
|
||||
output : "standalone"
|
||||
}
|
||||
```
|
||||
2. then at dist there is standalone folder is created go to that folder and do `npm i` and then go to root directory
|
||||
3. Remove the output standalone config and then build it again to have folder `.next`, copy this folder in standalone directory and when running `npm run start` it will run this build
|
||||
- remove type errors in nextjs build
|
||||
```js
|
||||
// in next.config.js
|
||||
module.exports = {
|
||||
typescript: {
|
||||
// !! WARN !!
|
||||
// Dangerously allow production builds to successfully complete even if
|
||||
// your project has type errors.
|
||||
// !! WARN !!
|
||||
ignoreBuildErrors: true,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,486 @@
|
|||
Coding 10 Data fetching
|
||||
|
||||
Data Fetching
|
||||
- Server components support various configurations for caching, revalidating and optimizing data fetching
|
||||
- Client components have to use third party libraries such as TanStack Query which offers robus APIs
|
||||
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
users
|
||||
page.jsx
|
||||
page.css
|
||||
```
|
||||
|
||||
In `src/app/users/page.jsx`
|
||||
```js
|
||||
import "./page.css";
|
||||
|
||||
function User(props) {
|
||||
const { id, name, username, email, phone } = props;
|
||||
|
||||
return (
|
||||
<div key={id} className="user">
|
||||
<div className="col1">
|
||||
<div>{name}</div>
|
||||
<div>{username} </div>
|
||||
</div>
|
||||
<div className="col2">
|
||||
<div className="">{email}</div>
|
||||
<div className="">{phone}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default async function UsersPage() {
|
||||
console.log("UsersPage loaded");
|
||||
|
||||
const response = await fetch("https://jsonplaceholder.typicode.com/users");
|
||||
|
||||
const users = await response.json();
|
||||
|
||||
console.log(users);
|
||||
|
||||
return (
|
||||
<div className="UsersPage">
|
||||
{users.map((user) => (
|
||||
<User
|
||||
id={user.id}
|
||||
name={user.name}
|
||||
username={user.username}
|
||||
email={user.email}
|
||||
phone={user.phone}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
In `src/app/users/page.css`
|
||||
```css
|
||||
body {
|
||||
background: rgb(20, 20, 20);
|
||||
}
|
||||
|
||||
.UsersPage {
|
||||
text-align: left;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: 2rem;
|
||||
padding: 4rem;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.UsersPage .user {
|
||||
min-width: 350px;
|
||||
width: 60%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
background: white;
|
||||
margin: auto;
|
||||
border: 1px solid grey;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.UsersPage .user .col1,
|
||||
.UsersPage .user .col2 {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* align-items: center; */
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.UsersPage .user .col2 {
|
||||
align-items: end;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**Loading and Error States**
|
||||
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
users
|
||||
page.jsx
|
||||
page.css
|
||||
error.jsx
|
||||
loading.jsx
|
||||
```
|
||||
|
||||
In `@/users/page.jsx`
|
||||
```js
|
||||
import { resolve } from "styled-jsx/css";
|
||||
import "./page.css";
|
||||
|
||||
function User(props) {
|
||||
const { id, name, username, email, phone } = props;
|
||||
|
||||
return (
|
||||
<div key={id} className="user">
|
||||
<div className="col1">
|
||||
<div className="font-bold">{name}</div>
|
||||
<div>{username} </div>
|
||||
</div>
|
||||
<div className="col2">
|
||||
<div className="">{email}</div>
|
||||
<div className="">{phone}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default async function UsersPage() {
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
console.log("UsersPage loaded");
|
||||
|
||||
const response = await fetch("https://jsonplaceholder.typicode.com/users1");
|
||||
|
||||
const users = await response.json();
|
||||
|
||||
console.log(users);
|
||||
|
||||
return (
|
||||
<div className="UsersPage">
|
||||
{users.map((user) => (
|
||||
<User
|
||||
id={user.id}
|
||||
name={user.name}
|
||||
username={user.username}
|
||||
email={user.email}
|
||||
phone={user.phone}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
In `@/users/page.css`
|
||||
```css
|
||||
body {
|
||||
background: rgb(20, 20, 20);
|
||||
}
|
||||
|
||||
.UsersPage {
|
||||
text-align: left;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-gap: 2rem;
|
||||
padding: 4rem;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.UsersPage .user {
|
||||
min-width: 350px;
|
||||
width: 60%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
background: white;
|
||||
margin: auto;
|
||||
border: 1px solid grey;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.UsersPage .user .col1,
|
||||
.UsersPage .user .col2 {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
/* align-items: center; */
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.UsersPage .user .col2 {
|
||||
align-items: end;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
In `@/users/loading.jsx`
|
||||
```js
|
||||
export default function LoadingPage() {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-screen">
|
||||
<div className="animate-spin rounded-full h-32 w-32 border-t-2 border-b-2 border-white"></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
In `@/users/error.jsx`
|
||||
```js
|
||||
"use client";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export default function ErrorPage({ error }) {
|
||||
useEffect(() => {
|
||||
console.error(`${error}`);
|
||||
}, [error]);
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-center h-screen">
|
||||
<div className="text-2xl text-red-500">Error fetching users data</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**JSON Server Setup**
|
||||
|
||||
- Install npm package `json-server@0.17.4`. Make sure that this is the version
|
||||
- At the root of project create 2 files named `db.json` and `server.js`.
|
||||
|
||||
In `db.json`type
|
||||
```json
|
||||
{
|
||||
"products": [
|
||||
{
|
||||
"id": 1,
|
||||
"title": "Product 1",
|
||||
"price": 800,
|
||||
"description": "Description 1"
|
||||
},
|
||||
|
||||
{
|
||||
"id": 2,
|
||||
"title": "Product 2",
|
||||
"price": 1000,
|
||||
"description": "Description 2"
|
||||
},
|
||||
|
||||
{
|
||||
"id": 3,
|
||||
"title": "Product 3",
|
||||
"price": 2500,
|
||||
"description": "Description 3"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
In `server.js`
|
||||
```js
|
||||
const jsonserver = require("json-server");
|
||||
const server = jsonserver.create();
|
||||
|
||||
const PORT = 3002;
|
||||
|
||||
const router = jsonserver.router("./db.json");
|
||||
const middlewares = jsonserver.defaults();
|
||||
|
||||
server.use(middlewares);
|
||||
|
||||
server.use((req, res, next) => {
|
||||
console.log("request recieved");
|
||||
res.header("Access-Control-Allow-Origin", "*");
|
||||
res.header(
|
||||
"Access-Control-Allow-Methods",
|
||||
"GET, POST, PUT, DELETE, PATCH, OPTIONS"
|
||||
);
|
||||
|
||||
res.header(
|
||||
"Access-Control-Allow-Headers",
|
||||
"Origin, X-Requested-With, Content-Type, Accept"
|
||||
);
|
||||
next();
|
||||
});
|
||||
|
||||
server.use(router);
|
||||
|
||||
server.listen(PORT, () => {
|
||||
console.log("JSON Server is running");
|
||||
});
|
||||
|
||||
```
|
||||
As port is 3002 so when we visit to `localhost:3002/products`. we get array of products
|
||||
|
||||
|
||||
Caching Data
|
||||
- By default, Next.js automatically catches the returned values of fetch in the Data Cache on the server.
|
||||
In `src/app/products/page.jsx`
|
||||
```js
|
||||
import "./page.css";
|
||||
|
||||
export default async function Products() {
|
||||
console.log("Products loaded");
|
||||
|
||||
const response = await fetch("http://localhost:3002/products");
|
||||
const products = await response.json();
|
||||
|
||||
return (
|
||||
<ul className="Products space-y-4 p-4">
|
||||
{products.map((product) => (
|
||||
<li className="p-4 bg-white shadow-md rounded-lg text-gray-700">
|
||||
<h2 className="text-xl font-semibold">{product.title}</h2>
|
||||
<p>{product.description}</p>
|
||||
<p className="text-lg font-medium">{product.price}</p>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**Data Cache**
|
||||
- It is a server-side cache that persists the result of data fteches across incoming server requests and deployments
|
||||
- It improves app performance and reduce costs by eliminating need to refetch data from data source with every request
|
||||
- 
|
||||
- When request is made instead of getting information from data source it checks if its exist on cache. If it does exist then it simply returns it otherwise it will get data from source, send back to client also saving it in cache.
|
||||
- This data cache is stored in `.next/cache`. One such is `fetch-cache` in this folder. It contains cached data of the routes.
|
||||
- Unlike browser cache this is server cache means even if we load this page in different browser or incognito mode we get same result
|
||||
- If we clear the cache file and restart json and next dev server then we will get updated value
|
||||
|
||||
|
||||
**Opt out of caching**
|
||||
- To simply opt out of caching when fetching, set field `cookie` as `no-store`.
|
||||
eg
|
||||
```js
|
||||
const response = await fetch("http://localhost:3002/products", {
|
||||
cache: "no-store",
|
||||
});
|
||||
```
|
||||
- When using `no-store` all subsequent fetch requests will also be out out of caching too so its wise to place those fetch requests where caching is needed to use before then those where caching is opted out
|
||||
- There is a workaround to use cache even after using it after fetch request with `cache` set as `no-store`
|
||||
Type the following at top of the code
|
||||
`export const fetchCache = "default-cache";`
|
||||
This is route level
|
||||
https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config#fetchcache
|
||||
|
||||
|
||||
Eg: In `src/app/products/page.jsx`
|
||||
```js
|
||||
import "./page.css";
|
||||
|
||||
export const fetchCache = "default-cache";
|
||||
|
||||
export default async function Products() {
|
||||
console.log("Products loaded");
|
||||
|
||||
const response = await fetch("http://localhost:3002/products", {
|
||||
cache: "no-store",
|
||||
});
|
||||
const products = await response.json();
|
||||
|
||||
const detailedResponse = await fetch("http://localhost:3002/products/1");
|
||||
const detailedData = await detailedResponse.json();
|
||||
console.log("detailedata: ", detailedData);
|
||||
return (
|
||||
<ul className="Products space-y-4 p-4">
|
||||
{products.map((product) => (
|
||||
<li className="p-4 bg-white shadow-md rounded-lg text-gray-700">
|
||||
<h2 className="text-xl font-semibold">{product.title}</h2>
|
||||
<p>{product.description}</p>
|
||||
<p className="text-lg font-medium">{product.price}</p>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Other values of fetchCache
|
||||
```js
|
||||
export const fetchCache = 'auto'
|
||||
// 'auto' | 'default-cache' | 'only-cache'
|
||||
// 'force-cache' | 'force-no-store' | 'default-no-store' | 'only-no-store'
|
||||
```
|
||||
- Another way is using dynamic functions ( cookies(), headers(), searchParams ). Make sure to use them before making fetch requests. fetch requests before using dynamic functions will be cached by dedault though
|
||||
Eg:
|
||||
```js
|
||||
import { cookies } from "next/headers";
|
||||
import "./page.css";
|
||||
|
||||
// export const fetchCache = "default-cache";
|
||||
|
||||
export default async function Products() {
|
||||
console.log("Products loaded");
|
||||
|
||||
const cookieStore = cookies();
|
||||
cookieStore.get("sd");
|
||||
|
||||
const detailedResponse = await fetch("http://localhost:3002/products/1");
|
||||
const detailedData = await detailedResponse.json();
|
||||
|
||||
const response = await fetch("http://localhost:3002/products", {
|
||||
cache: "no-store",
|
||||
});
|
||||
const products = await response.json();
|
||||
|
||||
console.log("detailedata: ", detailedData);
|
||||
return (
|
||||
<ul className="Products space-y-4 p-4">
|
||||
{products.map((product) => (
|
||||
<li className="p-4 bg-white shadow-md rounded-lg text-gray-700">
|
||||
<h2 className="text-xl font-semibold">{product.title}</h2>
|
||||
<p>{product.description}</p>
|
||||
<p className="text-lg font-medium">{product.price}</p>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**Request Memoization** (Client-side caching)
|
||||
- It is a technique that deduplicates requests for the same data within a single render pass. This feature is by default
|
||||
- This approach allows for re-use of data in a React Component tree, prevents redundant network calls
|
||||
- After data is fetched initially, result is stored in memory
|
||||
- When same data is needed across different components in a rout( eg in a layout, page and multiple components ), it eliminates the need to fetch data a the top of tree
|
||||
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
products
|
||||
layout.jsx
|
||||
page.jsx
|
||||
```
|
||||
|
||||
In `src/app/products/layout.jsx`
|
||||
```js
|
||||
export default async function LayoutPage({ children }) {
|
||||
const productresponse = await fetch("http://localhost:3002/products");
|
||||
const data = await productresponse.json();
|
||||
|
||||
console.log("product data :", data);
|
||||
|
||||
console.log("Product LayoutPage loaded");
|
||||
|
||||
return <>{children};</>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
this url is fetched in page.jsx too but at json server this route is accessed one time only bcz layout.jsx and page.jsx is in single render pass
|
||||
- 
|
||||
- When request is made it checks memory for the result. If not then it goes to server and in server it checks data cache then it checks data source.
|
||||
|
||||
Note: Its not limited to client side bcz components can be server component too
|
||||
|
||||
|
||||
Imp notes about it
|
||||
- Request memoization is a React future and not limited to nextjs. In React 19 request memization will no longer be default feature. So its possible then in future it will be no longer by default too
|
||||
- Memoization only applies to GET method in fetch requests.
|
||||
- It applies to react component tree and not extend to route handlers as they are not part of react component tree
|
||||
- For cases where fetch is not suitable (eg some database clients, CMS clients or GraphQL clients), we can use the React cache function to meoize functions.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
235
joplin notion extension/Web Development/React/next/Coding 2.md
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
Coding 2
|
||||
|
||||
**Private Folders**
|
||||
- In nextjs routing is based on folders so things like grouping and management for code is also done by project so there have to be folders which is not routable or write ui logic rather than routing logic. These folders r called private folders.
|
||||
- They begin with `_`(underscore). eg: `_lib`.
|
||||
- If we want underscore to be as part of route then use the prefix `%5F` which is url encoded form of underscore(`_`).
|
||||
|
||||
|
||||
**Route Groups**
|
||||
- Allows us to logically group our routes and project files without affecting the URL path structure.
|
||||
- Folder purpose is not for routing only but for grouping of various routes and we may not want to effect the url. Example if project structure
|
||||
```text
|
||||
src/app
|
||||
auth
|
||||
Login
|
||||
Register
|
||||
page.jsx
|
||||
````
|
||||
To access we need `localhost:3000/auth/register`. If we want to access via `localhost:3000/register` then we need to tell next that `auth` is route group. surround auth with parenthesis like this `(auth)`.
|
||||
Now
|
||||
```text
|
||||
src/app
|
||||
(auth)
|
||||
Login
|
||||
Register
|
||||
page.jsx
|
||||
````
|
||||
|
||||
|
||||
**Layout**
|
||||
- A page is UI that is unique to a route
|
||||
- A layout is UI that is shared between multiple pages in the app.
|
||||
Eg:
|
||||
In `src/app/layout.jsx`
|
||||
```jsx
|
||||
export const metadata = {
|
||||
title: "Next.js",
|
||||
description: "Generated by Next.js",
|
||||
};
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>
|
||||
<header style={{ background: "lightblue", padding: "1rem" }}>
|
||||
Head
|
||||
</header>
|
||||
{children}
|
||||
<footer style={{ background: "orange", padding: "1rem" }}>
|
||||
Footer
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Now every page.jsx content will be under this header and footer. and the routes ie folder inside app and all those nested one will inherit too
|
||||
|
||||
|
||||
**Route Group Layout**
|
||||
- We may not want the same layout for every nested route so to fix it we can use route groups for layout. Purpose being is to selectively apply layout to certain segments while leaving other unchanged
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
(auth)
|
||||
forgot-password
|
||||
(with-auth-layout)
|
||||
Login
|
||||
Register
|
||||
layout.jsx
|
||||
page.jsx
|
||||
```
|
||||
In `src/app/(auth)/(with-auth-layout)/layout.jsx` .
|
||||
```jsx
|
||||
export default function AuthLayout({ children }) {
|
||||
return (
|
||||
<div className="">
|
||||
<h2>Inner Layout</h2>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Now in `login` and `register` we would have
|
||||
```text
|
||||
Head
|
||||
Inner Layout
|
||||
Login
|
||||
Footer
|
||||
```
|
||||
This inner layout is added for login and password only and wont work for forgot-password page
|
||||
|
||||
|
||||
**Routing metadata**
|
||||
- Nextjs have metadata api to define metadata for each page
|
||||
- Medadata ensures accurate and relevant information is displayed when the page is shared or indexed.
|
||||
- Configuring metadata
|
||||
- Export static metadata object
|
||||
- Export a dynamic generateMetadata function
|
||||
**MetaData Rules**
|
||||
- Both layout.jsx and page.jsx files can export metadata. If defined in a layout, it applies to all pages in that layout, but defined in a page, then that page only.
|
||||
- Metadata is read in order ie from root level to final page level.
|
||||
- When there's metadata in multiple places for the same route, they get combined, but page metadata will replace layout metadata if they have the same properties
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
about
|
||||
page.jsx
|
||||
page.jsx
|
||||
layout.jsx
|
||||
```
|
||||
In `src/app/layout.jsx`
|
||||
```jsx
|
||||
|
||||
// object has to be 'metadata'
|
||||
export const metadata = {
|
||||
title: "Next.js",
|
||||
description: "Generated by Next.js",
|
||||
};
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
In `src/app/about/page.jsx`
|
||||
```jsx
|
||||
export const metadata = {
|
||||
title: "About me",
|
||||
};
|
||||
|
||||
export default function About() {
|
||||
return <h1>About me</h1>;
|
||||
}
|
||||
|
||||
```
|
||||
all the routes will inherit the metadata of rootlayout page but the metadata inside their own page will take more precedence.
|
||||
So for `localhost:3000/about` page title is 'About me' and descruption will be inherited by metadata object in `layout.jsx` in app folder.
|
||||
**Dynamic metadata**
|
||||
- Depends on dynamic info such as current route parameters, external data or metadata from parent segments
|
||||
For dynamic routes, metadata may have to dynamic too. instead of exporting the object function is exported which returns the metadata with dynamic information
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
products
|
||||
[productId]
|
||||
page.jsx
|
||||
page.jsx
|
||||
page.jsx
|
||||
layout.jsx
|
||||
````
|
||||
In `src/app/products/[productId]/page.jsx`
|
||||
```jsx
|
||||
|
||||
// function name has to be 'generateMetadata' case-sensitive
|
||||
export const generateMetadata = ({ params }) => {
|
||||
return {
|
||||
title: `Product ${params.productId}`,
|
||||
};
|
||||
};
|
||||
|
||||
export default function ProductDetails({ params }) {
|
||||
console.log("params: ", typeof params.productId);
|
||||
return <h1> Details about Product {params.productId}</h1>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
As fetch can be used so this function ie generateMetadata can be async too
|
||||
In `src/app/products/[productId]/page.jsx`
|
||||
```jsx
|
||||
|
||||
// function name has to be 'generateMetadata' case-sensitive
|
||||
export const generateMetadata = ({ params }) => {
|
||||
return {
|
||||
title: `Product ${params.productId}`,
|
||||
};
|
||||
};
|
||||
|
||||
export default function ProductDetails({ params }) {
|
||||
console.log("params: ", typeof params.productId);
|
||||
return <h1> Details about Product {params.productId}</h1>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**Title metadata**
|
||||
- Title needed not be a string and it can be a object too. This object has 3 properties ie `absolute`, `default`, `template`.
|
||||
- Default acts same as the one defined when title is string ie when inherited by other routes as when defined in layout.jsx
|
||||
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
blog
|
||||
page.jsx
|
||||
layout.jsx
|
||||
```
|
||||
In `src/app/layout.jsx`
|
||||
```jsx
|
||||
export const metadata = {
|
||||
title: {
|
||||
default: "Nextjs",
|
||||
template: "%s | end",
|
||||
},
|
||||
description: "Generated by Next.js",
|
||||
};
|
||||
```
|
||||
In `src/app/blog/page.jsx`
|
||||
```jsx
|
||||
export const metadata = {
|
||||
title: {
|
||||
default: "blog",
|
||||
},
|
||||
};
|
||||
```
|
||||
metadata of `localhost:3000/blog` is `blog | end`
|
||||
If
|
||||
```jsx
|
||||
export const metadata = {
|
||||
title: {
|
||||
absolute: "blog",
|
||||
},
|
||||
};
|
||||
```
|
||||
then
|
||||
metadata of `localhost:3000/blog` is `blog` as absolute will counter template too
|
||||
352
joplin notion extension/Web Development/React/next/Coding 3.md
Normal file
|
|
@ -0,0 +1,352 @@
|
|||
Coding 3
|
||||
|
||||
**Link Component Navigation**
|
||||
- To enable client-side navigation Next.js provides us with the Link component.
|
||||
- The `<Link>` component is a React component that extends the HTML `<a>` element and is primary way for navigation
|
||||
- To use it, we need to import it from 'next/link'.
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
blog
|
||||
page.jsx
|
||||
products
|
||||
page.jsx
|
||||
page.jsx
|
||||
```
|
||||
In `src/app/page.jsx`
|
||||
```jsx
|
||||
import Link from "next/link";
|
||||
|
||||
const Home = () => {
|
||||
return (
|
||||
<>
|
||||
<h1> Hello </h1>
|
||||
<Link href="/blog">Blog</Link>
|
||||
<Link href="/products">Products</Link>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Home;
|
||||
|
||||
```
|
||||
In `src/app/blog/page.jsx` `/` path is used to go to root page
|
||||
```jsx
|
||||
import Link from "next/link";
|
||||
|
||||
export default function Blog() {
|
||||
return (
|
||||
<>
|
||||
<h1>Blog</h1>
|
||||
<Link href="/">Home</Link>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
**For Dynamic Routes**
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
blog
|
||||
page.jsx
|
||||
products
|
||||
[productId]
|
||||
page.jsx
|
||||
page.jsx
|
||||
page.jsx
|
||||
```
|
||||
In `src/app/products/page.jsx`
|
||||
```jsx
|
||||
import Link from "next/link";
|
||||
|
||||
export default function ProductList() {
|
||||
const productId = 100;
|
||||
return (
|
||||
<>
|
||||
<h1>Product List</h1>
|
||||
<h2>Product 1</h2>
|
||||
<h2>Product 2</h2>
|
||||
<Link href={"products/3"} replace>
|
||||
{" "}
|
||||
<h2>Product 3</h2>{" "}
|
||||
</Link>
|
||||
<Link href={`products/${productId}`}>
|
||||
{" "}
|
||||
<h2>Product {productId}</h2>{" "}
|
||||
</Link>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
- Link for Dynmaic routes is generated just like we access the value of variable.
|
||||
With `replace` keyword we can clear the url stack history means after navigating to `localhost:3000/products/3` and when we click back button we will navigate to `localhost:3000` not `localhost:3000/products`.
|
||||
|
||||
|
||||
**Active Links**
|
||||
- First we need to create links for login, register, forgot-password in layout.jsx page for `(auth)`. So instead of creating these 3 links for each page ie login, register and forgot-password we used layout.jsx to serve this as template/same for all route groups.
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
(auth)
|
||||
login
|
||||
password
|
||||
forgot-password
|
||||
layout.jsx
|
||||
page.jsx
|
||||
```
|
||||
In `src/app/(auth)/layout.jsx`
|
||||
```jsx
|
||||
import Link from "next/link";
|
||||
|
||||
const navLinks = [
|
||||
{ name: "Register", href: "/register" },
|
||||
{ name: "Login", href: "/login" },
|
||||
{ name: "Forgot Password", href: "/forgot-password" },
|
||||
];
|
||||
|
||||
export default function OuterAuthLayout({ children }) {
|
||||
return (
|
||||
<div className="">
|
||||
{navLinks.map((link) => {
|
||||
return <Link href={link.href}>{link.name}</Link>;
|
||||
})}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
- So in order to style it we need to know the path of current url so we need to use the `usePathname` from 'next/navigation' hook. As we r using hook we need client side rendering for this and have to type `use client` at top in jsx file.
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
(auth)
|
||||
login
|
||||
password
|
||||
forgot-password
|
||||
layout.jsx
|
||||
style.css
|
||||
page.jsx
|
||||
```
|
||||
In `src/app/(auth)/layout.jsx`. Use the particular class for active link
|
||||
```jsx
|
||||
"use client";
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
|
||||
import "./style.css";
|
||||
|
||||
const navLinks = [
|
||||
{ name: "Register", href: "/register" },
|
||||
{ name: "Login", href: "/login" },
|
||||
{ name: "Forgot Password", href: "/forgot-password" },
|
||||
];
|
||||
|
||||
export default function OuterAuthLayout({ children }) {
|
||||
const pathname = usePathname();
|
||||
return (
|
||||
<div className="">
|
||||
{navLinks.map((link) => {
|
||||
const isActive = pathname.startsWith(link.href);
|
||||
return (
|
||||
<Link
|
||||
href={link.href}
|
||||
key={link.name}
|
||||
className={isActive ? "active-link" : ""}
|
||||
>
|
||||
{link.name}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
In `src/app/(auth)/style.css`
|
||||
```css
|
||||
a {
|
||||
margin: 0 1rem;
|
||||
color: blue;
|
||||
}
|
||||
|
||||
a.active-link {
|
||||
color: black;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**Navigating Programitically**
|
||||
- Instead of using jsx, javascript can be used too so for that we can use the hook ie `useRouter` from 'next/navigation'.
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
order-product
|
||||
page.jsx
|
||||
page.jsx
|
||||
```
|
||||
In `src/app/order-product/page.jsx`
|
||||
```jsx
|
||||
"use client";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
export default function OrderProduct() {
|
||||
const router = useRouter();
|
||||
const handleClick = () => {
|
||||
console.log("order placed");
|
||||
router.push("/");
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>Order Product</h1>
|
||||
<button onClick={handleClick}>Place Order</button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
router.push('/') will push the root route to url stack and when we click on back after going through homepage it will brink back to the page `localhost:3000/order-product`. In `Link` coponent there was a attribute named replace which clears the url stack so to do same programitically use `router.replace('/')`. Not only that but we can go to previous or next url stack too by `router.back()` and `router.forward()`
|
||||
|
||||
|
||||
**Templates**
|
||||
- Templates are similar to layouts in the way they wrap each child layout or page
|
||||
But with templates when a user navigates between routes that share a template, a new instance of component is mounted, DOM elements are recreated, state is not preserved.
|
||||
- So to only to be used once we dont have to conserve states and need a template to recreate pages so their states dont conflict with each other
|
||||
Without template
|
||||
```text
|
||||
src/app
|
||||
(auth)
|
||||
login
|
||||
password
|
||||
forgot-password
|
||||
layout.jsx
|
||||
style.css
|
||||
page.jsx
|
||||
```
|
||||
In `src/app/(auth)/layout.jsx`
|
||||
```jsx
|
||||
"use client";
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
|
||||
import "./style.css";
|
||||
|
||||
import { useState } from "react";
|
||||
|
||||
const navLinks = [
|
||||
{ name: "Register", href: "/register" },
|
||||
{ name: "Login", href: "/login" },
|
||||
{ name: "Forgot Password", href: "/forgot-password" },
|
||||
];
|
||||
|
||||
export default function OuterAuthLayout({ children }) {
|
||||
const pathname = usePathname();
|
||||
const [input, setInput] = useState("");
|
||||
|
||||
return (
|
||||
<div className="">
|
||||
<div className="">
|
||||
<input
|
||||
type="text"
|
||||
value={input}
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
{navLinks.map((link) => {
|
||||
const isActive = pathname.startsWith(link.href);
|
||||
return (
|
||||
<Link
|
||||
href={link.href}
|
||||
key={link.name}
|
||||
className={isActive ? "active-link" : ""}
|
||||
>
|
||||
{link.name}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
When we move to new route input will be same and wont be reset.
|
||||
**With templates**
|
||||
Just change the file name from layout.jsx to template.jsx and now input will be reset and nothing will be preserved.
|
||||
Some limitations though. If there is a route group(say named inner-auth) like this
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
(auth)
|
||||
(inner-auth)
|
||||
login
|
||||
password
|
||||
forgot-password
|
||||
template.jsx
|
||||
style.css
|
||||
page.jsx
|
||||
```
|
||||
In this case, states between `login` and `password` routes will be shared not with `forget-password` route though.
|
||||
|
||||
|
||||
**Loading UI**
|
||||
- Till now different files like `page.jsx`, `layout.jsx`, `not-found.jsx` and `template.jsx` have been used. There is another one ie `loading.jsx`.
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
blog
|
||||
first
|
||||
second
|
||||
loading.jsx
|
||||
layout.jsx
|
||||
page.jsx
|
||||
page.jsx
|
||||
```
|
||||
In `src/app/blog/loading.jsx`
|
||||
```jsx
|
||||
export default function LoadingBlog() {
|
||||
return (
|
||||
<div className="LoadingBlog">
|
||||
<h1>Loading</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
To test it, make sure that `src/app/blog/page.jsx` loads slower due to setTimeout. Make sure that layout.jsx wont load slow as first layout.jsx is loaded then loading.jsx contents then page.jsx.
|
||||
|
||||
In `src/app/blog/page.jsx`
|
||||
```jsx
|
||||
import Link from "next/link";
|
||||
|
||||
export const metadata = {
|
||||
title: {
|
||||
absolute: "blog",
|
||||
default: "blog",
|
||||
},
|
||||
};
|
||||
|
||||
function promiseSetTimeOut(time) {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, time);
|
||||
});
|
||||
}
|
||||
|
||||
export default async function Blog() {
|
||||
await promiseSetTimeOut(1000);
|
||||
return (
|
||||
<>
|
||||
<h1>Blog</h1>
|
||||
<Link href="/">Home</Link>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
160
joplin notion extension/Web Development/React/next/Coding 4.md
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
Coding 4
|
||||
|
||||
**Error Handling**
|
||||
- To handle errors, another file is there named `error.jsx`.
|
||||
- During development mode it will tell the detailed error ie where in the ocde there is error but in the production mode ie when we run `npm run build` then `npm run start` then we get different kind of error and to show specific message in that case
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
products
|
||||
[productId]
|
||||
reviews
|
||||
[reviewId]
|
||||
error.jsx
|
||||
page.jsx
|
||||
page.jsx
|
||||
|
||||
```
|
||||
In `src/app/products/[productId]/reviews/[reviewId]/page.jsx`
|
||||
```jsx
|
||||
import { notFound } from "next/navigation";
|
||||
|
||||
function getRandomInt(count) {
|
||||
return Math.floor(Math.random() * count);
|
||||
}
|
||||
|
||||
export default function ReviewDetail(prop) {
|
||||
console.log("params: ", prop.params);
|
||||
|
||||
if (Number(prop.params.reviewId) > 1000) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
if (getRandomInt(2) == 1) {
|
||||
throw new Error("error with review");
|
||||
}
|
||||
|
||||
return (
|
||||
<h1>
|
||||
Review {prop.params.reviewId} about product {prop.params.productId}
|
||||
</h1>
|
||||
);
|
||||
}
|
||||
```
|
||||
So to catch these errors and display them
|
||||
In `src/app/products/[productId]/reviews/[reviewId]/error.jsx`
|
||||
```jsx
|
||||
"use client";
|
||||
export default function ErrorBoundary({ error }) {
|
||||
return <div className="">Error in reviewId. Error is {error.message}</div>;
|
||||
}
|
||||
```
|
||||
Make sure that error boundary is client component
|
||||
- Automatically wrap a route segment and its nested children in a React Error Boundary
|
||||
- Create error UI tailored to specific segments using the file-system heirarchy to adjust granularity
|
||||
- Isolate errors to affected segments while keeping the rest of the application functional.
|
||||
- Add functionality to attempt to recover from an error without a full page reload
|
||||
|
||||
|
||||
Component Heirarchy
|
||||
```jsx
|
||||
<Layout>
|
||||
<Template>
|
||||
<ErrorBoundary fallback={<Error />} >
|
||||
<Suspense fallback={<Loading />}>
|
||||
<ErrorBoundary fallback={<NotFound />} >
|
||||
<Page />
|
||||
</ErrorBoundary>
|
||||
</Suspense>
|
||||
</ErrorBoundary>
|
||||
</Template>
|
||||
</Layout>
|
||||
```
|
||||
|
||||
|
||||
**Recovering from Errors**
|
||||
- In props of ErrorBoundary there is a property named error through which we can print error. Also there is one more field ie reset which tries to reload the component giving error in case it get resolved.
|
||||
- In order for the error to get resolved the component which was giving error must be client component too so use `use client;` at top in `page.jsx`.
|
||||
|
||||
In `src/app/products/[productId]/reviews/[reviewId]/error.jsx`
|
||||
```jsx
|
||||
"use client";
|
||||
export default function ErrorBoundary({ error, reset }) {
|
||||
return (
|
||||
<div className="">
|
||||
Error in reviewId. Error is {error.message} <br />
|
||||
<button onClick={reset}>Try again</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
**Handling Errors in Nested Routes**
|
||||
- Errors bubble up to the closest parent error boundary
|
||||
- An error.jsx file will cater to errors for all its nested child segments
|
||||
- By positioning error.jsx files at different levels in the nested folders of a route , we can achieve a more granular level of error handling.
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
products
|
||||
[productId]
|
||||
reviews
|
||||
[reviewId]
|
||||
error.jsx
|
||||
page.jsx
|
||||
page.jsx
|
||||
|
||||
```
|
||||
So here `error.jsx` is at `reviewsId` so layout.jsx at products folder so layout.jsx of products will render but for reviews folder , it wont as error bondary is for reviewsId so all the upper parents component will render.
|
||||
If we shift the `error.jsx` to `products` then products `layout.jsx` wont execute too.
|
||||
|
||||
**Handling errors in Layout**
|
||||
- It is true that error.jsx file should be as close as to route as possible but unlike page.jsx layout component will render before error component so if error occurs in layout then error.jsx at same route/folder wont work.
|
||||
- In such case error.jsx must be in parent folder for that route containing layout.jsx
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
products
|
||||
[productId]
|
||||
layout.jsx
|
||||
error.jsx
|
||||
page.jsx
|
||||
layout.jsx
|
||||
|
||||
```
|
||||
In `src/app/products/[productId]/layout.jsx`
|
||||
```jsx
|
||||
"use client";
|
||||
function getRandomInt(count) {
|
||||
return Math.floor(Math.random() * count);
|
||||
}
|
||||
|
||||
export default function ProductIdLayout({ children }) {
|
||||
if (getRandomInt(2) == 1) {
|
||||
throw new Error("error with review");
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<h2>Features Products</h2>
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
In `src/app/products/error.jsx`
|
||||
```jsx
|
||||
"use client";
|
||||
export default function ErrorBoundary({ error, reset }) {
|
||||
return (
|
||||
<div className="">
|
||||
Error in reviewId. Error is {error.message} <br />
|
||||
<button onClick={reset}>Try again</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,306 @@
|
|||
Coding 5 (Parallel Routes)
|
||||
|
||||
More advanced topics
|
||||
# **Parallel Routes**
|
||||
- Parallel routes are similar to using multiple React components in a layout.jsx file like this
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
complex-dashboard
|
||||
users.jsx
|
||||
reviews.jsx
|
||||
notifications.jsx
|
||||
page.jsx
|
||||
layout.jsx
|
||||
components
|
||||
card.jsx
|
||||
```
|
||||
|
||||
In `src/app/complex-dashboard/layout.jsx`
|
||||
```jsx
|
||||
import Notifications from "./notifications";
|
||||
import Reviews from "./reviews";
|
||||
import Users from "./users";
|
||||
|
||||
export default function ComplexDashboardLayout({ children }) {
|
||||
return (
|
||||
<>
|
||||
<div className="">{children}</div> {/* Contents from page.jsx */}
|
||||
<div style={{ display: "flex" }}>
|
||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
||||
<Users /> {/* Contents from users.jsx */}
|
||||
<Reviews /> {/* Contents from reviews.jsx */}
|
||||
</div>
|
||||
<div style={{ display: "flex", flex: 1 }}>
|
||||
<Notifications /> {/* Contents from notifications.jsx */}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
In `src/app/complex-dashboard/page.jsx`
|
||||
```jsx
|
||||
export default function ComplexDashboard() {
|
||||
return <h1>Complex Dashboard</h1>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
In `src/app/complex-dashboard/users.jsx`
|
||||
```jsx
|
||||
import Card from "../components/card";
|
||||
|
||||
export default function Users() {
|
||||
return <Card>Users</Card>;
|
||||
}
|
||||
|
||||
```
|
||||
Similarly in `reviews.jsx` and `notifications.jsx`
|
||||
|
||||
In `src/app/components/card.jsx`
|
||||
```jsx
|
||||
export default function Card({ children }) {
|
||||
const cardStyle = {
|
||||
padding: "100px",
|
||||
margin: "10px",
|
||||
boxShadow: "0 4px 8px 0 rgba(0,0,0,0.2)",
|
||||
border: "1px solid #ddd",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
};
|
||||
|
||||
return <div style={cardStyle}>{children}</div>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**Doing same with parallel routes**
|
||||
- We have to use slots as they help structure our content in modular fashion
|
||||
- We will use the '@folder_name' convention
|
||||
- Each slot is passed as a prop to its corresponding 'layout.jsx' file
|
||||
Transfer the files users.jsx, reviews.jsx and notifications.jsx like this
|
||||
```bash
|
||||
cd $projectRoot/src/app/complex-dashboard
|
||||
mv users.jsx @users/page.js
|
||||
mv reviews.jsx @reviews/page.js
|
||||
mv notifications.jsx @notifications/page.js
|
||||
```
|
||||
Make sure that instead of 'page.jsx' 'page.js' should be used as that is expected from slots. Components may not rendered if `page.jsx` is used. Sometimes slot is not added in next so restart the dev server in such case.
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
complex-dashboard
|
||||
@users
|
||||
page.js
|
||||
@reviews
|
||||
page.js
|
||||
@notifications
|
||||
page.js
|
||||
page.jsx
|
||||
layout.jsx
|
||||
components
|
||||
card.jsx
|
||||
```
|
||||
In `src/app/complex-dashboard/layout.jsx`
|
||||
```jsx
|
||||
export default function ComplexDashboardLayout({
|
||||
children,
|
||||
notifications,
|
||||
users,
|
||||
reviews,
|
||||
}) {
|
||||
console.log("users: ", users);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="">{children}</div> {/* Contents from page.jsx */}
|
||||
<div style={{ display: "flex" }}>
|
||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
||||
{users} {/* Contents from users.jsx */}
|
||||
{reviews} {/* Contents from reviews.jsx */}
|
||||
</div>
|
||||
<div style={{ display: "flex", flex: 1 }}>
|
||||
{notifications} {/* Contents from notifications.jsx */}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
Benefits of using parallel routes
|
||||
- Ability to split a single layout into various slots, making the code more manageable though it is also possible with components
|
||||
|
||||
Coming to main benefits which is not possible with components
|
||||
- Independent route handling
|
||||
Unlike components, these slots can have their own loading and error states as they r handled like other routes without changing the url stack
|
||||
This gives more control where different sections load at varying speeds or encounter unique errors.
|
||||

|
||||
- Sub navigation in routes
|
||||
- Each slot can function as their own mini application with their own navigation and state management.
|
||||
If we try to navigate to another route using components then it would be different as component is part of the page and when using `Link` component to change route then whole page has to be loaded so other component will not appear unless they r specifically rerendered in new page
|
||||

|
||||
|
||||
|
||||
|
||||
# Unmatched Routes
|
||||
- Adding a sub navigation in notifications slot
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
complex-dashboard
|
||||
@users
|
||||
page.js
|
||||
@reviews
|
||||
page.js
|
||||
@notifications
|
||||
archived
|
||||
page.jsx
|
||||
page.js
|
||||
page.jsx
|
||||
layout.jsx
|
||||
components
|
||||
card.jsx
|
||||
```
|
||||
|
||||
In `src/app/complex-dashboard/@notifications/archived/page.jsx`
|
||||
```jsx
|
||||
import Card from "@/app/components/card";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function Notifications() {
|
||||
return (
|
||||
<Card>
|
||||
<div>Archived Notifications</div>
|
||||
<Link href={"/complex-dashboard"}>Default</Link>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
In `src/app/complex-dashboard/@notifications/page.js`
|
||||
```jsx
|
||||
import Card from "@/app/components/card";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function Notifications() {
|
||||
return (
|
||||
<Card>
|
||||
<div>Notifications</div>
|
||||
<Link href={"/complex-dashboard/archived"}>Archived</Link>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
When user click on the link named 'Archived' then archived will be added in route so our route will change from `localhost:3000/complex-dashboard` to `localhost:3000/complex-dashboard/archived`.
|
||||
- In layout.jsx there r 4 slots ie props.children, users, reviews and notifications. At `localhost:3000/complex-dashboard/archived` props.children, users, reviews are unmatched routes as archived folder is inside notifications slot.
|
||||
- When navigating witin the UI and not adding `archived` directly with browser, nextjs retains the previously active state of a slot regardless of changes in the URL
|
||||
- During page reload or directly typing archived in url we will get the error 404 if default.jsx is not found in corresponding unmatched slots. Even if one default.jsx is missing in any unmatched slot 404 error will there instead of other matched components getting loaded.
|
||||
- Adding `default.jsx` in unmatched slot is neccessary as it serves as fallback to render contents when nextjs cannot retrieve a slot's active state from the current URL.
|
||||
- We can define the UI for unmatched routes in any way in default.jsx and also mirror the content found in corresponding page.jsx.
|
||||
Adding `default.jsx` in unmatched slots
|
||||
```bash
|
||||
# copying contents to default.jsx from page.jsx
|
||||
cd $projectRoot/src/app/complex-dashboard
|
||||
cp page.js default.js
|
||||
cp @users/page.js @users/default.js
|
||||
cp @reviews/page.js @reviews/default.js
|
||||
```
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
complex-dashboard
|
||||
@users
|
||||
default.js
|
||||
page.js
|
||||
@reviews
|
||||
default.js
|
||||
page.js
|
||||
@notifications
|
||||
archived
|
||||
page.jsx
|
||||
page.js
|
||||
default.js
|
||||
page.jsx
|
||||
layout.jsx
|
||||
components
|
||||
card.jsx
|
||||
```
|
||||
|
||||
|
||||
|
||||
# Conditional Routes
|
||||
- With parallel routes it is possible to have conditional routes like login page or register page depending upon state and benefits with loading and error state and sub navigation unlike using component directly.
|
||||
- Ternary operators can be used for conditional rendering
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
complex-dashboard
|
||||
@login.jsx
|
||||
default.js
|
||||
page.js
|
||||
@users
|
||||
default.js
|
||||
page.js
|
||||
@reviews
|
||||
default.js
|
||||
page.js
|
||||
@notifications
|
||||
archived
|
||||
page.jsx
|
||||
page.js
|
||||
default.js
|
||||
page.jsx
|
||||
layout.jsx
|
||||
components
|
||||
card.jsx
|
||||
```
|
||||
In `src/app/complex-dashboard/@login/page.js` and `src/app/complex-dashboard/@login/default.js`
|
||||
```jsx
|
||||
import Card from "@/app/components/card";
|
||||
|
||||
export default function Login() {
|
||||
return <Card>Please login to continue</Card>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
In `src/app/complex-dashboard/layout.jsx`
|
||||
```jsx
|
||||
export default function ComplexDashboardLayout({
|
||||
children,
|
||||
notifications,
|
||||
users,
|
||||
reviews,
|
||||
login,
|
||||
}) {
|
||||
// if true that 'please login to continue' section wont appear
|
||||
const isLoogedIn = false;
|
||||
return isLoogedIn ? (
|
||||
<>
|
||||
<div className="">{children}</div> {/* Contents from page.jsx */}
|
||||
<div style={{ display: "flex" }}>
|
||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
||||
{users} {/* Contents from users.jsx */}
|
||||
{reviews} {/* Contents from reviews.jsx */}
|
||||
</div>
|
||||
<div style={{ display: "flex", flex: 1 }}>
|
||||
{notifications} {/* Contents from notifications.jsx */}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
login
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
Make sure that default.js file also exist which can be same as page.js for login slot
|
||||
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
Coding 6(Intercepting Routes)
|
||||
|
||||
# Intercepting Routes
|
||||
|
||||
- Intercepting routes allow us to intercept or stop the default routing behaviour to present alternative view when navigating through UI, while still preserving the intended route
|
||||
So it is useful when we wanna show a route while keeping context of current page
|
||||

|
||||
As we can see that when clicked on image, rest of page is blurred and that image is overlayed over others while keeping rest of page/images in background.
|
||||
When page reloads or when we share the link to someone else the original image is shown and rest of page contents is lost.
|
||||
|
||||
|
||||
### Intercepting routes conventions
|
||||
- (.) to match segments on the same level
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
f1
|
||||
(.)f2
|
||||
page.jsx
|
||||
f2
|
||||
page.jsx
|
||||
page.jsx
|
||||
```
|
||||
In `src/app/f1/page.jsx`
|
||||
```jsx
|
||||
import Link from "next/link";
|
||||
|
||||
export default function F1() {
|
||||
return (
|
||||
<>
|
||||
<h1>F1 Page</h1>
|
||||
<Link href={"/f1/f2"}>F2</Link>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
In `src/app/f1/f2/page.jsx`
|
||||
```jsx
|
||||
export default function F2() {
|
||||
return (
|
||||
<>
|
||||
<h1>F2 Page</h1>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
In `src/app/f1/(.)f2/page.jsx`
|
||||
```jsx
|
||||
export default function F2() {
|
||||
return (
|
||||
<>
|
||||
<h1>(.) Intercepted F2 Page</h1>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
- (..) to match segments one level above
|
||||
```text
|
||||
src/app
|
||||
f1
|
||||
(.)f2
|
||||
page.jsx
|
||||
f2
|
||||
page.jsx
|
||||
|
||||
f3
|
||||
page.jsx
|
||||
f4
|
||||
(..)f3
|
||||
page.jsx
|
||||
page.jsx
|
||||
page.jsx
|
||||
```
|
||||
We can keep intercepted route of f3 inside folder f1 instead of inside f4 too and we wont need `(..)` too as `(.)` would suffice but when using lyout or template it is helpful to keep inside f4 rather inthan inside f1.
|
||||
In `src/app/f1/f4`
|
||||
```jsx
|
||||
import Link from "next/link";
|
||||
|
||||
export default function F4() {
|
||||
return (
|
||||
<>
|
||||
<h1>F4 Page</h1>
|
||||
<Link href={"/f1/f3"}>F3</Link>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
Same for `src/app/f1/f3` and `src/app/f1/f4/(..f3)` with their respective page name
|
||||
- (..)(..) to catch segments two level above. But this may have some issues
|
||||
- (...) to match segments from the root app directory
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
about
|
||||
intro
|
||||
page.jsx
|
||||
f1
|
||||
f4
|
||||
page.jsx
|
||||
(...)about
|
||||
intro
|
||||
page.jsx
|
||||
```
|
||||
In `src/app/f1/f4`
|
||||
```jsx
|
||||
import Link from "next/link";
|
||||
|
||||
export default function F4() {
|
||||
return (
|
||||
<>
|
||||
<h1>F4 Page</h1>
|
||||
<Link href={"/about/intro"}>Intro</Link>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
In `src/app/f1/f4/(...)about/intro/page.jsx`
|
||||
```jsx
|
||||
export default function Intro() {
|
||||
return (
|
||||
<>
|
||||
<h1>(...) Intercepted Intro</h1>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
In `src/app/about/intro`
|
||||
```jsx
|
||||
export default function Intro() {
|
||||
return <h1>Intro</h1>;
|
||||
}
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,408 @@
|
|||
Coding 7(RESTful Route handlers)
|
||||
- Unlike page routes, route handlers allow us to create RESTful endpoints, giving us full control over the response.
|
||||
- We dont have to create and configure a separate server for that
|
||||
- For making external API requests
|
||||
- For securing private keys
|
||||
|
||||
In `src/app/flashboard/route.js`
|
||||
```js
|
||||
export async function GET() {
|
||||
return new Response("flash board api data");
|
||||
}
|
||||
```
|
||||
|
||||
when visited to page `localhost:3000/flashboard` then it will represent this response
|
||||
|
||||
If there is page.jsx too like in `src/app/flashboard/page.js` then in this case page.jsx will take precedence over route.js and page.jsx content will be displayed. To avoid this make sure that page.jsx and route.jsx is never in same folder/route. So make sure to have different folder (say api) under flashboard folder and add route.jsx to that
|
||||
```text
|
||||
src/app
|
||||
flashboard
|
||||
api
|
||||
route.jsx
|
||||
page.jsx
|
||||
```
|
||||
|
||||
|
||||
**GET Request**
|
||||
|
||||
in `src/app/comments/data.js`
|
||||
```js
|
||||
export const comments = [
|
||||
{
|
||||
id: 1,
|
||||
text: "This is my first comment",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
text: "This is my second comment",
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
text: "This is my third comment",
|
||||
},
|
||||
];
|
||||
|
||||
```
|
||||
|
||||
in `src/app/comments/route.js`
|
||||
```js
|
||||
import { comments } from "./data";
|
||||
|
||||
export async function GET() {
|
||||
return Response.json(comments);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**POST Request**
|
||||
|
||||
in `src/app/comments/route.js`
|
||||
```js
|
||||
export async function POST(request) {
|
||||
const comment = await request.json();
|
||||
|
||||
const newcomment = {
|
||||
id: comments.length + 1,
|
||||
text: comment,
|
||||
};
|
||||
|
||||
comments.push(newcomment);
|
||||
|
||||
return new Response(JSON.stringify(newcomment), {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
status: 201,
|
||||
});
|
||||
}
|
||||
|
||||
```
|
||||
Every POST route handler recieved a request in form of object
|
||||
|
||||
|
||||
**Dynamic Route Handler**
|
||||
- for dynamic routes like `localhost:3000/comments/:id`
|
||||
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
comments
|
||||
[id]
|
||||
route.js
|
||||
route.js
|
||||
```
|
||||
|
||||
in `src/app/comments/[id]/route.js`
|
||||
```js
|
||||
import { comments } from "../data";
|
||||
|
||||
export async function GET(request, context) {
|
||||
const { params } = context;
|
||||
|
||||
const comment = comments.find(
|
||||
(comment) => comment.id === parseInt(params.id)
|
||||
);
|
||||
|
||||
return Response.json(comments);
|
||||
}
|
||||
|
||||
```
|
||||
Here we have other parameter which is a object that contains params
|
||||
|
||||
|
||||
**Handling PATCH request**
|
||||
|
||||
in `src/app/comments/[id]/route.js`
|
||||
```js
|
||||
export async function PATCH(request, { params }) {
|
||||
const body = await request.json();
|
||||
|
||||
const { text } = body;
|
||||
|
||||
console.log("text: ", text);
|
||||
|
||||
const index = comments.findIndex(
|
||||
(comment) => comment.id === parseInt(params.id)
|
||||
);
|
||||
|
||||
console.log("index : ", index);
|
||||
|
||||
comments[index]["text"] = text;
|
||||
|
||||
return Response.json(comments[index]);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**Handling DELETE request**
|
||||
|
||||
in `src/app/comments/[id]/route.js`
|
||||
```js
|
||||
export async function DELETE(request, { params }) {
|
||||
const index = comments.findIndex(
|
||||
(comment) => comment.id === parseInt(params.id)
|
||||
);
|
||||
|
||||
const deletedContext = comments[index];
|
||||
|
||||
comments.splice(index, 1);
|
||||
|
||||
return Response.json(deletedContext);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
**URL Query parameters**
|
||||
- To handle and parse query parameters like `localhost:3001/comments?s=first`
|
||||
we need to parameter in GET method.
|
||||
- The paramater is of type NextRequest and contains nextUrl and this contains searchParams field too. searchParams field contains get method through which we can get values of query parameters
|
||||
|
||||
In `src/app/comments/route.js`
|
||||
```js
|
||||
export async function GET(request) {
|
||||
const searchParams = request.nextUrl.searchParams;
|
||||
|
||||
const query = searchParams.get("s");
|
||||
|
||||
// if query is not null then only filter else print all comments
|
||||
const filteredComments = query
|
||||
? comments.filter((comment) => comment.text.includes(query))
|
||||
: comments;
|
||||
|
||||
return Response.json(filteredComments);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**Redirects in URL**
|
||||
- Just like useRouter. useRouter is for client side and redirect is for server side.
|
||||
to navigate to `/comments` in client side
|
||||
```js
|
||||
"use client";
|
||||
import { useRouter } from "next/navigation";
|
||||
|
||||
const router = useRouter()
|
||||
router.push('/comments')
|
||||
|
||||
```
|
||||
to navigate `/comments` in server side
|
||||
```js
|
||||
import {redirect} from "next/navigation";
|
||||
redirect('/comments');
|
||||
|
||||
```
|
||||
|
||||
In `src/app/comments/[id]/route.js`
|
||||
|
||||
```js
|
||||
export async function GET(request, context) {
|
||||
const { params } = context;
|
||||
// if id is invalid then redirects
|
||||
if (parseInt(params.id) > comments.length) {
|
||||
redirect("/comments");
|
||||
}
|
||||
|
||||
const comment = comments.find(
|
||||
(comment) => comment.id === parseInt(params.id)
|
||||
);
|
||||
|
||||
return Response.json(comment);
|
||||
}
|
||||
```
|
||||
- When using this it sends status code as 307 which means for redirect
|
||||
|
||||
|
||||
**Headers in Route Handlers**
|
||||
- HTTP headers represent the metadata associated with an API request and response
|
||||
- Request Headers
|
||||
- Sent by client to server containing info about request so server process it accordingly
|
||||
- `User-Agent` indicates browser and OS
|
||||
- `Accept` : indicates content-type that client will understand and expects server to send it in 'Content-Type' in response headers
|
||||
- `Authorization` : fr authenticate itself to server. Eg : Bearer token
|
||||
- Reponse Headers
|
||||
- Sent by server to client containing info abour server and data sent in reponse
|
||||
- `Content-Type` : indicates media type of response. eg : 'application/json', 'text/plain', 'text/html'.
|
||||
|
||||
- Headers Class can be used to create object after passing `req.headers` in its constructor
|
||||
- there is a method named `headers` which can be imported from 'next/headers'
|
||||
|
||||
In `src/app/flashboard/api/route.js`
|
||||
```js
|
||||
import { headers } from "next/headers";
|
||||
|
||||
export async function GET(request) {
|
||||
const reqHeaders = new Headers(request.headers);
|
||||
const headerList = headers();
|
||||
|
||||
console.log(reqHeaders.get("Authorization"));
|
||||
console.log(headerList.get("Authorization"));
|
||||
|
||||
return new Response("<h1> flash board api data </h1>", {
|
||||
headers: {
|
||||
// "Content-Type": "text/html",
|
||||
"Content-Type": "text/plain",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**Cookies in route handlers**
|
||||
- Cookies are piece of data server sends of web browser
|
||||
- Browser may store cookie and send it back to same server with later requests
|
||||
- Purposes
|
||||
- session management like logins and shopping carts
|
||||
- Personalization like user preferences and themes
|
||||
- Tracking like recording and anakyzing user behavior
|
||||
- It can be defined by adding `Set-Cookie` field in headers and value if the form of `<name>=<value>`
|
||||
- There r 2 ways. one is through standard way ie using `request.cookies.get('<cookie_name>')` and other is using cookies method from 'next/headers' module. this method will return an object which has get and set methods
|
||||
|
||||
In `src/app/flashboard/api/route.js`
|
||||
|
||||
```js
|
||||
import { headers, cookies } from "next/headers";
|
||||
|
||||
export async function GET(request) {
|
||||
const reqHeaders = new Headers(request.headers);
|
||||
const headerList = headers();
|
||||
|
||||
cookies().set("resultsPerPage", "20");
|
||||
const theme = request.cookies.get("theme");
|
||||
const resultsPerPage = request.cookies.get("resultsPerPage");
|
||||
|
||||
console.log(reqHeaders.get("Authorization"));
|
||||
console.log(headerList.get("Authorization"));
|
||||
|
||||
console.log(theme);
|
||||
console.log("resultsperpage: ", cookies().get("resultsPerPage"));
|
||||
// console.log(resultsPerPage);
|
||||
|
||||
return new Response("<h1> flash board api data </h1>", {
|
||||
headers: {
|
||||
// "Content-Type": "text/html",
|
||||
"Content-Type": "text/plain",
|
||||
"Set-Cookie": "theme=dark",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**Caching in Route Handlers**
|
||||
- Route Handlers are cached by default when using GET method with response object in Nextjs
|
||||
|
||||
In `src/app/time/route.js`
|
||||
```js
|
||||
export async function GET() {
|
||||
const time = new Date().toLocaleTimeString();
|
||||
|
||||
return Response.json({ time });
|
||||
}
|
||||
|
||||
```
|
||||
In this one it will show try to cache the time so after the first request when we send this request `localhost:3000/time` result will be cached and will not be updated after furthur load
|
||||
- How to opt out of caching
|
||||
- dynamic mode in Segment Config Option
|
||||
- using Request object with GET method
|
||||
- employing dynamic functions like headers() and cookies()
|
||||
- using any HTTP method other than GET
|
||||
|
||||
```js
|
||||
// by default dynamic is 'auto'
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export async function GET() {
|
||||
const time = new Date().toLocaleTimeString();
|
||||
|
||||
return Response.json({ time });
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Middleware
|
||||
- Middleware in Next.js is powerful feature for intercepting and controlling flow of requests and responses within applications
|
||||
- Does all of this at global level which significantly ehance feature like redirection, URL rewrites, authentication, headers and cookies management and more.
|
||||
- Middleware allows to specify paths where it will be active
|
||||
- Custom matcher config (like switch case)
|
||||
- Conditional statements (if/else type)
|
||||
|
||||
In `src/middleware.js`
|
||||
Custom matcher config
|
||||
```js
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export function middleware(request) {
|
||||
return NextResponse.redirect(new URL("/", request.url));
|
||||
}
|
||||
|
||||
export const config = {
|
||||
matcher: "/profile",
|
||||
};
|
||||
|
||||
```
|
||||
this will redirect every request whole path is `/profile` to `/`
|
||||
- this redirection can be done in `profile` route itself but point of using middleware is change it without profile route is reached. Maybe that route has more code to be exeuted and we dont wanna temper with it so using middleware solved this issue or maybe that route dont exist or requires authentication
|
||||
|
||||
Conditional statements
|
||||
```js
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export function middleware(request) {
|
||||
if (request.nextUrl.pathname === "/profile") {
|
||||
return NextResponse.redirect(new URL("/hello", request.url));
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- rewrites : map a new path to an existing app component path without displaying URL changes to the user. it will route the traffic while masking original path. its limitation is that it cant route traffic to external domain
|
||||
https://docs.digitalocean.com/products/app-platform/how-to/url-rewrites/
|
||||
|
||||
In `src/middleware.js`
|
||||
```js
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export function middleware(request) {
|
||||
if (request.nextUrl.pathname === "/profile") {
|
||||
return NextResponse.rewrite(new URL("/hello", request.url));
|
||||
}
|
||||
}
|
||||
```
|
||||
so url will be displayed as `localhost:3000/profile` but content will be of `localhost:3000/hello`
|
||||
- Cookies and Headers : Cookies and headers can also be added to middleware. Advantage is being setting them for global level for all routes
|
||||
|
||||
In `src/middleware.js`
|
||||
```js
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export function middleware(request) {
|
||||
// refers to next response in middleware chain as reponse is to be send to next middleware or route handler is
|
||||
// current middleware is last one
|
||||
const response = NextResponse.next();
|
||||
|
||||
const themePreference = request.cookies.get("theme");
|
||||
|
||||
if (!themePreference) {
|
||||
response.cookies.set("theme", "dark");
|
||||
}
|
||||
|
||||
response.headers.set("custom-header", "custom-value");
|
||||
|
||||
return response;
|
||||
|
||||
// if (request.nextUrl.pathname === "/profile") {
|
||||
// return NextResponse.rewrite(new URL("/hello", request.url));
|
||||
// }
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,380 @@
|
|||
Coding 8 (Rendering)
|
||||
|
||||
RSC in detail https://www.youtube.com/watch?v=X2eUQIjNxCQ
|
||||
|
||||
- Rendering is the rocess that transforms the code we write into user interfaces
|
||||
- choosing right time and place for renering is key for performant application
|
||||
- CSR (Client Side Rendering), SSR (Server Side Rendering), RSC(React Server Components)
|
||||
|
||||
|
||||
### Rendering in React
|
||||
- when client requests for web page it gets html + js file and html file is mostly blank and have link to js file
|
||||
- **Client side rendering**
|
||||
- Method of rendering where compoent code is transformed to user interface directly within the brower is known as client side rendering
|
||||
- 
|
||||
- It became standard for SPAs(Single Page Apps)
|
||||
- Drawbacks of CSR
|
||||
- SEO : Generating HTML that mainly contains a single div tagis not optimal for SEO, as it provides little content for search engines to index
|
||||
- Performance : Having browser handle all the work, fetcjing data, computing UI and making the HTML interactive can slow things down so users might see a blank screen or loading spinner while page loads
|
||||
- Each new feature added to applicaton increases size of js bundle prolonging the wait time for users to see the UI and this delay is noticed by users with slow internet connection
|
||||
- **Server side Rendering**(SSR)
|
||||
- To overcome drawbacks of CSR, gatsby and next started to use SSR.
|
||||
- 
|
||||
- Even though some problems related to SEO and performance was solved UI was still non interactive and for that Js reference is used
|
||||
- Hydration
|
||||
- Hydration is the process of attaching event listeners to the DOM, to make the static HTML interactive. Behind the scenes, hydration is done with the hydrateRoot
|
||||
React API.
|
||||
- When static html is served then react takes control in browser reconstructing component tree in memory
|
||||
- It carefully plans the placement of interactive elements within this tree and react proceeds to bind necessary js logic to these elementsonalities required for a ully interactive iser experience
|
||||
- This involves initializing application statem attaching event handlers for actions like click and mouseovers, setting up dynamic functionalities required for interactive User experience
|
||||
- 
|
||||
- Server side solutions
|
||||
1. Static Site Generation : When the application is deployed to the server which results in pages that are already rendered and ready to serve . It is ideal for content that doesnt change often like blog posts.
|
||||
2. Server side rendering : Renders pages on demand in response to user requests . Sutable for personalized content where the HTML depends on the logged in user.
|
||||
Server-Side Rendering was a significant improvement over CSR
|
||||
- **Drawbacks of SSR** (All or Nothing waterfall)
|
||||
1. You have to fetch everything before you can show anything
|
||||
- Components cannot start rendering and then pause or wait while data is being loaded.
|
||||
- If a component needs to fetch data from database or another source(like API) then fetching must be completed before the server can behin rendering the page
|
||||
- This can delay server's response time to browser as server must finish collecting all necessary data before any part of page can be sent to client
|
||||
2. We have to load everything before we can hydrate anything
|
||||
- For successful hydration, where react adds interactivity to server rendered HTML, component tree must match exactly of server generated component tree
|
||||
- This means all JS for components must be loaded on client befire we can start hydrating any of them
|
||||
3. We have to hydrate everything before u can interact with anything
|
||||
- As React hydrates component tree in single pass means all components must be hydrated before they can be interacted with any of them
|
||||
4. Summary
|
||||
- load data for entire page for viewing
|
||||
- load js for entire page
|
||||
- hydrate entire page
|
||||
5. It is inefficient if some parts of app is slower than others as often with real world apps
|
||||
|
||||
|
||||
### Suspense SSR Architecture
|
||||
- To combat all or nothing waterfall of SSR `<suspense>` component can be used which unlock 2 major SSR features
|
||||
1. HTML streaming on the server
|
||||
2. Selective hydration on the client
|
||||
|
||||
Rendering components without suspense
|
||||

|
||||
|
||||
**Rendering components with suspense**
|
||||

|
||||
- So html streaming will occur and once the server is ready for data for main section with inline script tag which contains minmal js to position that component so that it will be visible for ths user
|
||||
|
||||
This solve 2 problems ie
|
||||
- No need to fetch everything before to show anything
|
||||
- if particular section delays the initial html then it can seemlessly inthegrated to stream later.
|
||||
- this is how it faciliates server side html streaming
|
||||
|
||||
Remaining challenges
|
||||
- client side hydration cant start unless the js of main section is loaded
|
||||
- and if the js bundle for the main section is large then it will delay process significantly
|
||||
|
||||
As html streaming section is solved but we also need to load js separtely for main section so other section can become interactive too and dont wait for main component
|
||||
|
||||
**Code rendering**
|
||||
- Code splitting allows us to mark specific code segments as not immediately necessary for loading, signalling your bundler to segregate them into separate `<scripts>` tags.
|
||||
- Using `React.lazy` for code splitting enables you to separate the main section's code from primary js bindle
|
||||
- The js containing React and the code for the entire application, excluding the main section can now be downloaded independently by the client without having to wait for main section's code.
|
||||
|
||||
for the following architecture
|
||||
```text
|
||||
src/app
|
||||
about
|
||||
Main.jsx
|
||||
page.jsx
|
||||
```
|
||||
|
||||
In `src/app/about/Page.jsx`
|
||||
|
||||
```js
|
||||
"use client";
|
||||
|
||||
// function promiseSetTimeOut(time) {
|
||||
// return new Promise((resolve, reject) => {
|
||||
// setTimeout(() => {
|
||||
// resolve();
|
||||
// }, time);
|
||||
// });
|
||||
// }
|
||||
|
||||
function delayForDemo(promise) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, 3000);
|
||||
}).then(() => promise);
|
||||
}
|
||||
|
||||
import { Suspense, lazy } from "react";
|
||||
|
||||
|
||||
// Main component will be loaded 3s later
|
||||
const Main = lazy(() => delayForDemo(import("./Main")));
|
||||
|
||||
export default function DashBoard() {
|
||||
console.log("page loaded");
|
||||
|
||||
// const getDatainDelay = async (time, data) => {
|
||||
// await promiseSetTimeOut(time);
|
||||
// // return <button onClick={clickHandler}>data</button>;
|
||||
// return <button>data</button>;
|
||||
// };
|
||||
|
||||
return (
|
||||
<>
|
||||
<header>
|
||||
<h1>Dashboard</h1>
|
||||
</header>
|
||||
<Suspense fallback={<button>Loading..</button>}>
|
||||
{/* <main>{getDatainDelay(500, "hey this is main loaded")}</main> */}
|
||||
<Main />
|
||||
</Suspense>
|
||||
|
||||
<footer>copyright by nextjs</footer>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
In `src/app/about/Main.jsx`
|
||||
|
||||
```js
|
||||
export default function Main() {
|
||||
console.log("main loaded");
|
||||
|
||||
return <div className="Main">ghh</div>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Selective hydration on the Client
|
||||
- Wrapping the main section with `Suspense` rest of page will not be prevented from streaming and hydrating
|
||||
- 
|
||||
|
||||
|
||||
Drawbacks of Suspense SSR
|
||||
- In react there is CSR so even if there is non interactive UI it will needs to undergo hydration
|
||||
|
||||
|
||||
## React Server Components (RSC)
|
||||
- It is new architecture designed by React team
|
||||
- The approach aims to leverage the strnegths of both server and client environments optimizing for efficiency
|
||||
- It introduces a dual component model
|
||||
- client components
|
||||
- server components
|
||||
- The distinction is not based on functionality of the components but rather on where they execute and specific environments they are designed to interact with.
|
||||
|
||||
|
||||
RSC and Next.js
|
||||
- App router in Next.js is built on the RSC architecture
|
||||
|
||||
|
||||
|
||||
### RSC Rendering Lifecycle
|
||||
**RSC Loading Sequence**
|
||||

|
||||
https://nextjs.org/docs/app/building-your-application/rendering/client-components
|
||||
- Browser sends request to the server about route.
|
||||
- Nextjs recieves the request and match server component(SC) respective for the route
|
||||
- Nextjs instructs react to render server component
|
||||
- React render the server component and any child component that r part of server component converting them to RSC payload.
|
||||
If any of server component suspends then react pauses rendering of subtree (child components along with it) and sends a placeholder value instead meanwhile client components are prepared with instructions for later in the life cycle.
|
||||
- This RSC payload is used by next which contains client component instruction to generate HTML for both components(client and server) on the server for the route
|
||||
- Generated html is streamed to the client along with RSC payload which reconcile the client and server components in order to update the DOM ie progressively render UI. this checking/matching of server and client component trees (ensures that the client-side representation of a component matches the server-side-rendered HTML that was initially sent to the browser. ) is important for maintaining consistency.
|
||||
- Finally hydration happens which converts it into interactive UI by attaching event listeners
|
||||
|
||||
|
||||
**RSC Update Sequence**
|
||||
Related to refresing parts of the app
|
||||

|
||||
- Browser requests refetch of specic UI such as a full route.
|
||||
- Next matches SC component and instruct react to render server component and react render components like the initial loading step.
|
||||
- Unlike initial loading there is no HTML generation and this RSC payload is progressively streamed back to client
|
||||
- On recieving route is re rendered using this RSC payload which is then reconiled and merged with new rendered output with existing component on screen.
|
||||
- This UI description is in JSON format and not HTML, react can update DOM while preserving crucial UI updates such as focus or input values.
|
||||
|
||||
|
||||
## Server rendering Strategies
|
||||
- Static rendering
|
||||
- Dynamic rendering
|
||||
- Streaming
|
||||
|
||||
|
||||
### Static rendering
|
||||
- Generate HTML pages at time of building our applications. Means all data and content of web page is prepared in advanced.
|
||||
- This approach means results can be cached by CDN and served to client instantly
|
||||
- Able to share the rendered work to different users resulting in significant performace boost for application
|
||||
- Useful for blogs, e-commerce product pages, documentation and marketing pages
|
||||
|
||||
|
||||
**How to Statically Render?**
|
||||
- It is default rendering strategy in the app router and all routes are automatically prepared at build time without additional setup
|
||||
|
||||
|
||||
Production vs Dev Server
|
||||
- For production,an optimized build is created once
|
||||
- In development it is inefficient to build app after every changes
|
||||
- in production builds, page is pre-rendered once build command is run
|
||||
- in development mode, page will be pre-rendered for every request.
|
||||
|
||||
.next folder
|
||||
- when building this is the output we get this
|
||||

|
||||
- The size is the amount of assets downloaded to perform a client-side transition to that page (after you've paid the "first load" for a different page). Means when we go from page A to B then the assets required which is basically difference as for navigating not all the assets is required as most of them r initially loaded
|
||||
- First Load JS is the total amount of assets your users will download when visiting the page from the server instead of navigating as initially nothing is loaded.
|
||||
- First load js is the important metric for performance
|
||||
https://github.com/vercel/next.js/pull/12034
|
||||
https://github.com/vercel/next.js/issues/10565
|
||||
|
||||
`.rsc` files
|
||||
- these are the compact string representation of virtual DOM and includes abbreviations, internal references and encoded special meanings
|
||||
- for the server components these `.rsc` files contain text which is displayed on web page too. Means it include rendered result of server component
|
||||

|
||||
- for the client components it contains placeholders/instructions instead means a refernce to chunks js file.
|
||||

|
||||
- This chunk js file referened by client component rsc is necessary for reconcilation and hydration
|
||||
|
||||
|
||||
**Prefetching**
|
||||
- Prefetching is a technique used to preload a route in the background before the user navigates to it
|
||||
- Routes are fetched automatically as they become visible in user's viewport when page first loads or it comes to view through scrolling
|
||||
- For static routes, entire route is prefetched and catched by default.
|
||||
- When homepage is loaded, nextjs prefetches the route whose links are there in homepage means `Link` components with those routes
|
||||
|
||||
|
||||
### Dynamic rendering
|
||||
- It is server rendering strategy where routes are rendered separately for each user at a request time
|
||||
- Useful when a route has personalized data or cookies info or url search params that can only be known at request time.
|
||||
- News website, personalized e-commerce pages and social media feeds
|
||||
|
||||
|
||||
**How to dynamically render**
|
||||
- During rendering, if dynmaic function is discovered then nextjs will switch to dynmaic rendering for whole route
|
||||
- In nextjs fynmaic functions are `cookies()`, `headers()` and `searchParams` and using any of these will switch to dynamic rendering at request time for the route.
|
||||
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
static
|
||||
page.jsx
|
||||
about
|
||||
page.jsx
|
||||
layout.jsx
|
||||
page.jsx
|
||||
```
|
||||
|
||||
|
||||
In `src/app/static/page.jsx`
|
||||
```js
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
export default function Static() {
|
||||
|
||||
// to force dynamaic rendering
|
||||
const cookieStore = cookies();
|
||||
const theme = cookieStore.get("theme");
|
||||
console.log("theme: ", theme);
|
||||
|
||||
return (
|
||||
<div className="Static">
|
||||
<h1>Static</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
- After building we get this output in terminal
|
||||

|
||||
This `/static` route will be dynmiacally rendered means it will not be rendered on build but rendered on nodejs when request is made
|
||||
Also in `.next` there will be no `static.html` like about and root route have
|
||||
|
||||
|
||||
### Streaming
|
||||
- Streaming is a strategy for allowing for progressive UI rendering from the server.
|
||||
- Work is divided into chunks and streamed to client as soon its ready
|
||||
- Enables users to get intitial look immediately and wait for whole page to load progressively
|
||||
- Streaming is integrated into nexjs app router by default
|
||||
|
||||
```text
|
||||
src/app
|
||||
product-detail
|
||||
page.jsx
|
||||
components
|
||||
product.jsx
|
||||
reviews.jsx
|
||||
layout.jsx
|
||||
page.jsx
|
||||
```
|
||||
|
||||
In `src/app/components/product.jsx`
|
||||
|
||||
```js
|
||||
const DELAYTIME = 2000;
|
||||
|
||||
export async function Product() {
|
||||
await new Promise((resolve) => setTimeout(resolve, DELAYTIME));
|
||||
return <div>Product</div>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
In `src/app/components/reviews.jsx`
|
||||
|
||||
```js
|
||||
const DELAYTIME = 4000;
|
||||
|
||||
export async function Reviews() {
|
||||
await new Promise((resolve) => setTimeout(resolve, DELAYTIME));
|
||||
return <div>Reviews</div>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
In `src/app/product-detail/page.jsx`
|
||||
|
||||
Without using suspense
|
||||
|
||||
```js
|
||||
import { Product } from "../components/product";
|
||||
import { Reviews } from "../components/reviews";
|
||||
|
||||
export default function ProductDetail() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Product Detail Page</h1>
|
||||
<Product />
|
||||
<Reviews />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
The page will take 4s to load bcz the reviews page is taking that much time and page will only load once all the component is rendered.
|
||||
So to have a fallback till those components are loaded so that user can see the page atleast use suspense
|
||||
|
||||
With suspense
|
||||
|
||||
```js
|
||||
import { Suspense } from "react";
|
||||
import { Product } from "../components/product";
|
||||
import { Reviews } from "../components/reviews";
|
||||
|
||||
export default function ProductDetail() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Product Detail Page</h1>
|
||||
<Suspense fallback={<p>Loading Product...</p>}>
|
||||
<Product />
|
||||
</Suspense>
|
||||
<Suspense fallback={<p>Loading Reviews...</p>}>
|
||||
<Reviews />
|
||||
</Suspense>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,508 @@
|
|||
Coding 9 (Composition Patterns)
|
||||
|
||||
Server Components
|
||||
- Fetching data
|
||||
- Directly accessing backend resources
|
||||
- Protecting sensitive information (like access tokens and API keys) on the server
|
||||
- Keeping large dependencies server-side helping in reducing client side javascript
|
||||
|
||||
|
||||
Client Components
|
||||
- Adding interactivity and handling event listeners
|
||||
- Managing state and lifecycle effects ( useState(), useReducer(), useEffect() )
|
||||
- Using browser-exclusive APIs
|
||||
- Custom hooks
|
||||
- React Class components
|
||||
|
||||
|
||||
## Server-only code
|
||||
- Its not wise to include server side code to prevent exposing logic, api keys or data also it may not work on client too
|
||||
- So its important to have a clear boundary
|
||||
- Create server side functions in different files and import `server-only` module in that file(containing server side function) which will give error at build time if its code is used in client components
|
||||
```text
|
||||
src/app
|
||||
utils
|
||||
server-utils.jsx
|
||||
server-route
|
||||
page.jsx
|
||||
client-route
|
||||
page.jsx
|
||||
```
|
||||
|
||||
In `src/app/utils/server-utils.jsx`
|
||||
```js
|
||||
import "server-only";
|
||||
|
||||
export const ServerSideFunction = () => {
|
||||
console.log(
|
||||
`use multiple libraries,
|
||||
use environment variables,
|
||||
interact with a database,
|
||||
process confidential information`
|
||||
);
|
||||
|
||||
return "server result";
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
In `src/app/server-route/page.jsx`
|
||||
```js
|
||||
import { ServerSideFunction } from "../utils/server-utils";
|
||||
|
||||
export default function ServerRoutePage() {
|
||||
console.log("Server router rendered");
|
||||
|
||||
const result = ServerSideFunction();
|
||||
return (
|
||||
<>
|
||||
<h1>ServerRoutePage</h1>
|
||||
<p>{result}</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
In `src/app/client-route/page.jsx`
|
||||
```js
|
||||
"use client";
|
||||
|
||||
import { ServerSideFunction } from "../utils/server-utils";
|
||||
|
||||
export default function ClientRoutePage() {
|
||||
console.log("Client route rendered");
|
||||
const result = ServerSideFunction();
|
||||
return (
|
||||
<>
|
||||
<h1>ClientRoutePage</h1>
|
||||
<p>{result}</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**Third Party Packages**
|
||||
- third party packages in npm dont use 'use client' directive so they cant be used in server components so we need to encapsulate them in another client component and use it instead
|
||||
- It is possible to use nested client side component inside server side component
|
||||
Example : Using `react-slick` package
|
||||
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
components
|
||||
ImageSlider.jsx
|
||||
ImageSlider.css
|
||||
utils
|
||||
server-utils.jsx
|
||||
server-route
|
||||
page.jsx
|
||||
client-route
|
||||
page.jsx
|
||||
```
|
||||
|
||||
In `src/app/components/ImageSlider.jsx`
|
||||
```js
|
||||
"use client";
|
||||
|
||||
// import { ServerSideFunction } from "../utils/server-utils";
|
||||
|
||||
import Slider from "react-slick";
|
||||
|
||||
// Import css files
|
||||
import "slick-carousel/slick/slick.css";
|
||||
import "slick-carousel/slick/slick-theme.css";
|
||||
import "./ImageSlider.css";
|
||||
|
||||
export default function ImageSlider() {
|
||||
console.log("Client route rendered");
|
||||
// const result = ServerSideFunction();
|
||||
|
||||
var settings = {
|
||||
dots: true,
|
||||
infinite: true,
|
||||
speed: 500,
|
||||
slidesToShow: 1,
|
||||
slidesToScroll: 1,
|
||||
};
|
||||
|
||||
return (
|
||||
// <>
|
||||
// <h1>ClientRoutePage</h1>
|
||||
// <p>{result}</p>
|
||||
// </>
|
||||
|
||||
// <Slider {...settings}>
|
||||
<Slider {...settings}>
|
||||
<div className="fit-con">
|
||||
<img src="https://picsum.photos/id/34/367/267" alt="picsum" />
|
||||
</div>
|
||||
<div className="fit-con">
|
||||
<img src="https://picsum.photos/id/35/367/267" alt="picsum" />
|
||||
</div>
|
||||
<div className="fit-con">
|
||||
<img src="https://picsum.photos/id/37/367/267" alt="picsum" />
|
||||
</div>
|
||||
<div className="fit-con">
|
||||
<img src="https://picsum.photos/id/41/367/267" alt="picsum" />
|
||||
</div>
|
||||
<div className="fit-con">
|
||||
<img src="https://picsum.photos/id/40/367/267" alt="picsum" />
|
||||
</div>
|
||||
<div className="fit-con">
|
||||
{/* <img src="https://picsum.photos/id/39/367/267" alt="picsum" /> */}
|
||||
<h1>6</h1>
|
||||
</div>
|
||||
</Slider>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
In `src/app/components/ImageSlider.css`
|
||||
|
||||
```css
|
||||
.fit-con {
|
||||
display: flex !important;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
In `src/app/server-route/page.jsx`
|
||||
```js
|
||||
import ImageSlider from "../components/ImageSlider";
|
||||
import { ServerSideFunction } from "../utils/server-utils";
|
||||
|
||||
export default function ServerRoutePage() {
|
||||
console.log("Server router rendered");
|
||||
|
||||
const result = ServerSideFunction();
|
||||
return (
|
||||
<>
|
||||
<h1>ServerRoutePage</h1>
|
||||
<p>{result}</p>
|
||||
<div style={{ width: "367px", margin: "auto" }}>
|
||||
<ImageSlider />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**Context Providers**
|
||||
- Context providers are typically rendered near the root of an application to share global application state and logic. Eg : App theme
|
||||
- React context is not supported in Server Compinent so just like encapusalating third package in separate client component we need to do same for this
|
||||
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
layout.jsx
|
||||
client-route
|
||||
page.jsx
|
||||
components
|
||||
theme-provider.jsx
|
||||
|
||||
```
|
||||
|
||||
In `src/app/components/theme-provider.jsx`
|
||||
|
||||
```js
|
||||
"use client";
|
||||
|
||||
import { createContext, useContext } from "react";
|
||||
|
||||
const defaultTheme = {
|
||||
colors: {
|
||||
primary: "#007bff",
|
||||
secondary: "#6c757d",
|
||||
},
|
||||
};
|
||||
|
||||
const ThemeContext = createContext(defaultTheme);
|
||||
|
||||
export const ThemeProvider = ({ children }) => {
|
||||
return (
|
||||
<ThemeContext.Provider value={defaultTheme}>
|
||||
{children}
|
||||
</ThemeContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useTheme = () => useContext(ThemeContext);
|
||||
export { ThemeContext };
|
||||
|
||||
```
|
||||
|
||||
In `src/app/layout.jsx`
|
||||
|
||||
```js
|
||||
import { Inter } from "next/font/google";
|
||||
import { ThemeProvider } from "./components/theme-provider";
|
||||
|
||||
|
||||
|
||||
|
||||
export const metadata = {
|
||||
title: "Create Next App",
|
||||
description: "Generated by create next app",
|
||||
};
|
||||
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<ThemeProvider>
|
||||
<body>{children}</body>
|
||||
</ThemeProvider>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
In `src/app/client-route/page.jsx`
|
||||
|
||||
```js
|
||||
"use client";
|
||||
|
||||
import { useContext } from "react";
|
||||
import { ThemeContext } from "../components/theme-provider";
|
||||
|
||||
export default function ClientRoutePage() {
|
||||
const theme = useContext(ThemeContext);
|
||||
|
||||
return (
|
||||
<h1
|
||||
style={{
|
||||
color: theme.colors.secondary,
|
||||
}}
|
||||
>
|
||||
Client Route
|
||||
</h1>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
To update the context value, use useState and transfer state, stateChanger t value of context provider
|
||||
```js
|
||||
import ReactDOM from "react-dom";
|
||||
import React, { useState } from "react";
|
||||
|
||||
import authContext from "./authContext";
|
||||
import Login from "./Login";
|
||||
|
||||
const App = () => {
|
||||
const [authenticated, setAuthenticated] = useState(false);
|
||||
|
||||
return (
|
||||
<authContext.Provider value={{ authenticated, setAuthenticated }}>
|
||||
<div> user is {`${authenticated ? "" : "not"} authenticated`} </div>
|
||||
<Login />
|
||||
</authContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById("container"));
|
||||
```
|
||||
|
||||
|
||||
## Client-only Code
|
||||
- To prevent unintended server side usage of client code we can install and import package `client-only`
|
||||
|
||||
|
||||
Client Component Placement
|
||||
- It is recommended to position client components lower in the component tree
|
||||
- Once the component is client component all the child component becomes client components too
|
||||
```text
|
||||
src/app
|
||||
components
|
||||
navbar.jsx
|
||||
navlink.jsx
|
||||
navsearch.jsx
|
||||
landing-page
|
||||
page.jsx
|
||||
```
|
||||
|
||||
In components
|
||||
```js
|
||||
|
||||
// navlink.jsx
|
||||
export default function Navlink() {
|
||||
console.log("Navlink loaded");
|
||||
|
||||
return <div className="Main">NavLink</div>;
|
||||
}
|
||||
|
||||
//navsearch.jsx
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
|
||||
export default function NavSearch() {
|
||||
const [search, setSearch] = useState("");
|
||||
|
||||
console.log("NavSearch loaded2");
|
||||
|
||||
return <div className="Main">NavSearch</div>;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//navbar.jsx
|
||||
import Navlink from "./navlink";
|
||||
import NavSearch from "./navsearch";
|
||||
|
||||
export default function NavBar() {
|
||||
console.log("navbar loaded");
|
||||
return (
|
||||
<>
|
||||
<div className="">NavBar</div>
|
||||
<Navlink />
|
||||
<NavSearch />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
- useState hook can be used in navbar too but since its usage is required only in navsearch file so its best to use it there otherwise navbar needs to be a client component and navlink will be client component too
|
||||
|
||||
In `src/app/landing-page.jsx`
|
||||
```js
|
||||
import NavBar from "../components/navbar";
|
||||
|
||||
export default function LandingPage() {
|
||||
return (
|
||||
<div className="">
|
||||
<h1>Landing Page</h1>
|
||||
<NavBar />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**Interleaving Server and Client components**
|
||||
- Server component cannot be directly used inside client component as they are automatically converted to client component by default
|
||||
- So a workaround is needed for this ie passing server component as prop to client component
|
||||
|
||||
```text
|
||||
src/app
|
||||
interleaving
|
||||
page.jsx
|
||||
components
|
||||
client-component.jsx
|
||||
server-component.jsx
|
||||
```
|
||||
|
||||
In `src/app/server-component.jsx`
|
||||
```js
|
||||
import fs from "fs";
|
||||
|
||||
|
||||
export default function ServerComponent() {
|
||||
console.log("ServerComponent loaded");
|
||||
|
||||
const fileBuffer = fs.readFileSync("package.json");
|
||||
|
||||
return (
|
||||
<div className="ServerComponent">
|
||||
<h1>Server Component</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Following wont work and will give error that fs is not working as server component which is children of client component becomes client component
|
||||
|
||||
In `src/app/interleaving.jsx`
|
||||
```js
|
||||
import ClientComponent from "../components/client-component";
|
||||
|
||||
|
||||
export default function InterleavingPage() {
|
||||
console.log("InterleavingPage loaded");
|
||||
|
||||
return (
|
||||
<div className="InterleavingPage">
|
||||
<ClientComponent />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
In `src/app/client-component.jsx`
|
||||
```js
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import ServerComponent from "./server-component";
|
||||
|
||||
export default function ClientComponent() {
|
||||
console.log("client component loaded");
|
||||
|
||||
const [state, seyState] = useState();
|
||||
|
||||
return (
|
||||
<div className="client-component">
|
||||
<h1>Client Component</h1>
|
||||
<ServerComponent />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Passing server component as props instead
|
||||
|
||||
In `src/app/interleaving.jsx`
|
||||
```js
|
||||
import ClientComponent from "../components/client-component";
|
||||
import ServerComponent from "../components/server-component";
|
||||
|
||||
export default function InterleavingPage() {
|
||||
console.log("InterleavingPage loaded");
|
||||
|
||||
return (
|
||||
<div className="InterleavingPage">
|
||||
<ClientComponent>
|
||||
<ServerComponent />
|
||||
</ClientComponent>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
In `src/app/client-component.jsx`
|
||||
```js
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
// import ServerComponent from "./server-component";
|
||||
|
||||
export default function ClientComponent({ children }) {
|
||||
console.log("client component loaded");
|
||||
|
||||
const [state, seyState] = useState();
|
||||
|
||||
return (
|
||||
<div className="client-component">
|
||||
<h1>Client Component</h1>
|
||||
{children}
|
||||
{/* <ServerComponent /> */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
252
joplin notion extension/Web Development/React/next/Coding.md
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
Coding
|
||||
|
||||
**Routes**
|
||||
- Create another folder in app folder named 'about'. In about create a file named page.jsx and type following
|
||||
```js
|
||||
export default function About() {
|
||||
return <h1>About me</h1>;
|
||||
}
|
||||
|
||||
```
|
||||
- Do same with 'Profile'
|
||||
```js
|
||||
export default function Profile() {
|
||||
return <h1>Profile</h1>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
File Structure is
|
||||
|
||||
```text
|
||||
src/app
|
||||
about
|
||||
page.jsx
|
||||
profile
|
||||
page.jsx
|
||||
page.jsx
|
||||
layout.jsx
|
||||
````
|
||||
|
||||
**Nested Routes**
|
||||
|
||||
- means more folders say (first and second in blog folder and blog in app folder)
|
||||
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
blog
|
||||
first
|
||||
page.jsx
|
||||
second
|
||||
page.jsx
|
||||
page.jsx
|
||||
layout.jsx
|
||||
````
|
||||
|
||||
**Dynamic routes**
|
||||
- pages with custom params in url
|
||||
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
products
|
||||
[productId]
|
||||
page.jsx
|
||||
page.jsx
|
||||
page.jsx
|
||||
layout.jsx
|
||||
````
|
||||
|
||||
`src/app/products/page.jsx`
|
||||
```js
|
||||
export default function ProductDetails() {
|
||||
return <h1> Details about Product</h1>;
|
||||
}
|
||||
|
||||
```
|
||||
`src/app/products/[productId]/page.jsx`
|
||||
```jsx
|
||||
export default function ProductDetails({ params }) {
|
||||
return <h1> Details about Product {params.productId}</h1>;
|
||||
}
|
||||
|
||||
```
|
||||
or if its typescript then
|
||||
```tsx
|
||||
export default function ProductDetails({ params } :
|
||||
{params: {productId: string};
|
||||
}) {
|
||||
return <h1> Details about Product {params.productId}</h1>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Each function contains parameter object which has property params. This params is also object which contain property productId which is of type string
|
||||
|
||||
|
||||
**Nested Dynamic routes**
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
products
|
||||
[productId]
|
||||
reviews
|
||||
[reviewsId]
|
||||
page.jsx
|
||||
page.jsx
|
||||
page.jsx
|
||||
page.jsx
|
||||
layout.jsx
|
||||
````
|
||||
In `src/app/products/[productId]/reviews/[reviewId]/page.jsx`
|
||||
```jsx
|
||||
export default function ReviewDetail(prop) {
|
||||
return (
|
||||
<h1>
|
||||
Review {prop.params.reviewId} about product {prop.params.productId}
|
||||
</h1>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
Here prop will contain params, params will contain 2 fiels ie productId and reviewId and these both r strings. in `localhost:3000/products/1/reviews/2` output is
|
||||
`params: { productId: '1', reviewId: '2' }`
|
||||
|
||||
**Catching Segments**
|
||||
- Even with nested dynamic routes we may not know what type of routes or how much nesting is needed bcz page may contain dynamic links so to solve it catching such segments is required.
|
||||
Structure
|
||||
```text
|
||||
src/app
|
||||
docs
|
||||
[...slug]
|
||||
page.jsx
|
||||
page.jsx
|
||||
layout.jsx
|
||||
````
|
||||
In `src/app/docs/[...slug]/page.jsx`
|
||||
```jsx
|
||||
export default function Slug({ params }) {
|
||||
console.log("params: ", params);
|
||||
|
||||
if (params.slug.length === 1) {
|
||||
return <h1>only 1 {params.slug[0]}</h1>;
|
||||
} else if (params.slug.length === 2) {
|
||||
return (
|
||||
<h1>
|
||||
only 2 {params.slug[0]} and {params.slug[1]}
|
||||
</h1>
|
||||
);
|
||||
}
|
||||
|
||||
return <h1> no one :( </h1>;
|
||||
}
|
||||
|
||||
```
|
||||
here params is object which will contain field named slug which is array of strings and contain all params after that. so if url `localhost:3000/docs/doc1/rev/rev1` then slug will be `['doc1', 'rev','rev1']`
|
||||
|
||||
the route `[...slug]` will only be visited if there r params after docs. To make sure that `page.jsx` works too then we need to use optional catch all. to do that enclose `[...slug]` with one more square bracket like this `[[...slug]]`. and at `localhost:3000/docs` `no one` will be showed.
|
||||
Optional catch all
|
||||
In `src/app/docs/[[...slug]]/page.jsx`
|
||||
```jsx
|
||||
export default function Slug({ params }) {
|
||||
console.log("params: ", params);
|
||||
|
||||
if (params.slug?.length === 1) {
|
||||
return <h1>only 1 {params.slug[0]}</h1>;
|
||||
} else if (params.slug?.length === 2) {
|
||||
return (
|
||||
<h1>
|
||||
only 2 {params.slug[0]} and {params.slug[1]}
|
||||
</h1>
|
||||
);
|
||||
}
|
||||
|
||||
return <h1>no one :(</h1>;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
**Custom Not-Found**
|
||||
- By default when we visit a route which is not configured then error message is displayed of nextjs default configuration. So for custom one
|
||||
Create file named `not-found.jsx` in app folder
|
||||
|
||||
In `src/app/not-found.jsx`
|
||||
```jsx
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<div className="">
|
||||
<h2>Page not found</h2>
|
||||
<p>Not able to find requested resource</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
so for unconfigured url this page will be displayed
|
||||
In dynamic routes, params can be checked using if and if edge condition for error pass then this page can be displayed
|
||||
```jsx
|
||||
// importing notFound from 'next/navigation'
|
||||
import { notFound } from "next/navigation";
|
||||
|
||||
export default function ReviewDetail(prop) {
|
||||
console.log("params: ", prop.params);
|
||||
|
||||
if (Number(prop.params.reviewId) > 1000) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
return (
|
||||
<h1>
|
||||
Review {prop.params.reviewId} about product {prop.params.productId}
|
||||
</h1>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
As `not-found.jsx` is in app folder so all folders under this will inherit this not-found page. So if we wanna have custom one according to folder then create `not-found.jsx` for specific folder
|
||||
So in `src/app/products/[productId]/reviews/[reviewId]/page.jsx`
|
||||
```jsx
|
||||
export default function notfoundRev() {
|
||||
return <h1>Review not found</h1>;
|
||||
}
|
||||
|
||||
```
|
||||
So now this page will be displayed
|
||||
|
||||
|
||||
**File Collocation**
|
||||
- `page.jsx` is important as it acts like a index.html for html css project, main() function in java or C. So next will try to find this file inside the folder and there must be one function which must be exported as default using `export default`.
|
||||
|
||||
In `src/app/dashboard/line-chart.jsx`
|
||||
```jsx
|
||||
export default function LineChart() {
|
||||
return <h1>Line Chart</h1>;
|
||||
}
|
||||
```
|
||||
In `src/app/dashboard/page.jsx`
|
||||
```jsx
|
||||
import LineChart from "./line-chart";
|
||||
|
||||
function BarChart() {
|
||||
return <h1>Bar Chart</h1>;
|
||||
}
|
||||
|
||||
function DashBoard() {
|
||||
return <h1>Dashboard</h1>;
|
||||
}
|
||||
|
||||
export default function Main() {
|
||||
return (
|
||||
<div className="">
|
||||
<LineChart />
|
||||
<BarChart />
|
||||
<DashBoard />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
- nextjs alternative : remix
|
||||
Initialization
|
||||
https://yewtu.be/watch?v=__mSgDEOyv8
|
||||
|
||||
- Use this to setup nextjs
|
||||
`npx create-next-app@latest myapp`
|
||||
Then `npm run dev` to run it
|
||||
- To run a production build
|
||||
`npm run build` then
|
||||
`npm run start`
|
||||
- Running on different port
|
||||
In `package.json`
|
||||
```json
|
||||
"scripts": {
|
||||
"dev": "next dev -p 3001",
|
||||
"build": "next build",
|
||||
"start": "next start -p 3001",
|
||||
"lint": "next lint"
|
||||
},
|
||||
```
|
||||
- running it as serverless mode, generate SSG
|
||||
in next.config.js, do following for static export
|
||||
```js
|
||||
/**
|
||||
* @type {import('next').NextConfig}
|
||||
*/
|
||||
const nextConfig = {
|
||||
output: 'export',
|
||||
|
||||
// Optional: Change links `/me` -> `/me/` and emit `/me.html` -> `/me/index.html`
|
||||
// trailingSlash: true,
|
||||
|
||||
// Optional: Prevent automatic `/me` -> `/me/`, instead preserve `href`
|
||||
// skipTrailingSlashRedirect: true,
|
||||
|
||||
// Optional: Change the output directory `out` -> `dist`
|
||||
// distDir: 'dist',
|
||||
}
|
||||
|
||||
module.exports = nextConfig
|
||||
```
|
||||
55
joplin notion extension/Web Development/React/next/Theory.md
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
Theory
|
||||
https://www.youtube.com/watch?v=r8nXMA_pf0w : importance of nextjs
|
||||
|
||||
https://nextjs-doc.surge.sh/docs/next/Theory
|
||||
|
||||
- Uses react to building user interfaces
|
||||
- Extra features are routing, optimized rendering, data fetching, bundling , compiling and more
|
||||
|
||||
|
||||
Why Learn nextjs
|
||||
1. **Routing**: file based routing so no need to install third party routng packages and configure it.
|
||||
2. **API Routes**: api supports a nextjs is full stack framework
|
||||
3. **Rendering** : both client and server side rendering.
|
||||
4. Styling : Supports css modules, tailwind css
|
||||
5. Optimization : optimization for images, fonts and scripts
|
||||
|
||||
### Project Structure
|
||||
|
||||
- package.json : contains dependencies and scripts
|
||||
- next.config.js : for nextjs
|
||||
|
||||
|
||||
**Folders**
|
||||
- .next : this folder generated when we run dev or build scripts and using this we get output. its included in `.gitignore`
|
||||
- public :holds static assets to be served like images and SVGs
|
||||
- src : most important folder. It contains app folder inside it by default which is also called app router. Inside it, there r some files.
|
||||
- globals.css : like index.css in react
|
||||
- layout.js : like index.js
|
||||
- page.js : like App.js
|
||||
- Flow of control
|
||||
package.json -> layout.js -> page.js -> browser
|
||||
|
||||
|
||||
|
||||
**React Server Components**
|
||||
1. Server Components
|
||||
- Default component
|
||||
- Ability to run task like reading file or fetching data from data base.
|
||||
- They cant use hooks or handle user interaction.
|
||||
2. Client Components
|
||||
- To create a Client Component, add `use client` at top of component file
|
||||
- They cant read files but can use hooks and manage user interaction
|
||||
|
||||
|
||||
**Routing**
|
||||
- It has file file system based routing
|
||||
- URL paths which user can access in browser are defined by files and folders in your codebase
|
||||
|
||||
|
||||
**Framwork Conventions**
|
||||
1. Routes in the app folder
|
||||
2. Every file corresponding to the routes must be placed inside the page.jsx or page.tsx
|
||||
3. Every folder corresponds to a path segment in the browser URL.
|
||||
It has convention over configuration process for routing
|
||||
|
||||
45
joplin notion extension/Web Development/React/next/Tips.md
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
Tips
|
||||
|
||||
- To import anything relative to src directory use `@` like following code
|
||||
Structure
|
||||
```text
|
||||
src
|
||||
app
|
||||
page.jsx
|
||||
components
|
||||
card.jsx
|
||||
```
|
||||
In `src/app/page.jsx`
|
||||
```jsx
|
||||
import Card from '@/components/card'
|
||||
|
||||
export default function App(){
|
||||
<>
|
||||
<Card>Tools</Card>
|
||||
</>
|
||||
}
|
||||
```
|
||||
In `src/components/card`
|
||||
```jsx
|
||||
export default function Card({ children }) {
|
||||
const cardStyle = {
|
||||
padding: "100px",
|
||||
margin: "10px",
|
||||
boxShadow: "0 4px 8px 0 rgba(0,0,0,0.2)",
|
||||
border: "1px solid #ddd",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
};
|
||||
|
||||
return <div style={cardStyle}>{children}</div>;
|
||||
}
|
||||
|
||||
```
|
||||
- multiple root layouts
|
||||
https://www.youtube.com/watch?v=X9_XqeqWBR0
|
||||
|
||||
Route grouping will be used so remove layout,jsx from root and instead use them in route group folders. Multiple layouts at same root is possible but not multiple pages so at whichever route there is page.jsx that will be considered as default route
|
||||
Next.js App Router Multiple Root Layouts: Explained With Examples.mp4
|
||||
https://files.catbox.moe/eiy18h.mp4
|
||||
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
Installation
|
||||
|
||||
```bash
|
||||
# install the cli app
|
||||
npx proton-native-cli init my-app
|
||||
# move to your project directory
|
||||
cd my-app
|
||||
|
||||
# run your app
|
||||
npm run start
|
||||
# OR to run with hot reloading
|
||||
npm run dev
|
||||
```
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
Packaging
|
||||
|
||||
- Creating the binary
|
||||
```bash
|
||||
npm run build # Transpile our code. If you have any extra files other than
|
||||
# app.js and index.js, make sure they are included in the build
|
||||
# script in package.json, so that they get transpiled also.
|
||||
|
||||
mkdir out
|
||||
npx nexe bin/index.js -o out/my-app # Create our binary
|
||||
```
|
||||
In nexe there might be the error as may not build by default when running in first time so use this
|
||||
`npx nexe bin/index.js -bo --verbose out/my-app # Create our binary`
|
||||
Here -b is --build
|
||||
Also there can be other error so go to `~/.nexe/...` and `../deps/v8/src/base/logging.h` and `../deps/v8/src/base/macro.h` and include library cstdint `#include <cstdint>`
|
||||
|
||||
**The packaged appimage would be 180mb+. Also 180mb+ ram**
|
||||
|
||||
As nexe takes 1hr to build so use already compiled version
|
||||
https://www.mediafire.com/file/gnob3ywpvq9te7a/nexe_archive.7z/file
|
||||
25
joplin notion extension/Web Development/React/router.md
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
router
|
||||
|
||||
- When using react router if we try to add direct links like using anchor tag it wont work in build ie production mode so its better to use `useNavigate` method of `react-router-dom`.
|
||||
- Alternatively if we really want to do that manually its possible with live-server command but with some modification in configs
|
||||
Create `app.js` and use `npm init -y` and `npm i live-server` and add following config in app.js
|
||||
https://github.com/ritwickdey/vscode-live-server/issues/72
|
||||
```js
|
||||
var liveServer = require("live-server");
|
||||
|
||||
var params = {
|
||||
port: 8181, // Set the server port. Defaults to 8080.
|
||||
host: "0.0.0.0", // Set the address to bind to. Defaults to 0.0.0.0 or process.env.IP.
|
||||
root: ".", // Set root directory that's being served. Defaults to cwd.
|
||||
open: false, // When false, it won't load your browser by default.
|
||||
ignore: 'scss,my/templates', // comma-separated string for paths to ignore
|
||||
file: "index.html", // When set, serve this file (server root relative) for every 404 (useful for single-page applications)
|
||||
wait: 1000, // Waits for all changes, before reloading. Defaults to 0 sec.
|
||||
// mount: [['/components', './node_modules']], // Mount a directory to a route.
|
||||
logLevel: 2, // 0 = errors only, 1 = some, 2 = lots
|
||||
middleware: [function(req, res, next) { next(); }] // Takes an array of Connect-compatible middleware that are injected into the server middleware stack
|
||||
};
|
||||
liveServer.start(params);
|
||||
|
||||
```
|
||||
- Or maybe use HashRouter instead of Browserrouter. that may resolve issue
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
static html generator
|
||||
- https://github.com/react-static/react-static
|
||||
- Consider using static site generators like Jekyll, Hugo, or Gatsby. While Gatsby is built on React, it allows you to build static sites where the final output is plain HTML, CSS, and JavaScript.
|
||||
- https://nextjs.org/docs/pages/building-your-application/deploying/static-exports
|
||||
https://github.com/vercel/next.js/discussions/44641 : for handling slugs
|
||||
|
||||
|
||||
- also use strapi : using nodejs to generate static files
|
||||
- using jsdom
|
||||
- sveltekit : svelte:sveletekit :: react:next
|
||||
- React-Snap for converting existing react app by pre-rendering them. limit : not for multiple pages
|
||||
- or using eleventy-plugin-react when using 11ty
|
||||
https://github.com/kaicataldo/eleventy-plugin-
|
||||
demo : endeavouros/Videos/imp/others/11ty/react/
|
||||
|
||||
|
||||
Converting a React or any other JavaScript framework code to static HTML typically involves pre-rendering or server-side rendering (SSR). This can be particularly useful for SEO purposes or for situations where a static file is needed. Here are steps to convert React code to static HTML:
|
||||
|
||||
### Method 1: Using ReactDOMServer for Static HTML Export
|
||||
|
||||
1. **Install Necessary Libraries**:
|
||||
You will need to have `react`, `react-dom`, and `react-dom/server` installed. If you are not working within an existing React app, create one using Create React App.
|
||||
|
||||
```sh
|
||||
npx create-react-app my-static-site
|
||||
cd my-static-site
|
||||
npm install react react-dom react-dom/server
|
||||
```
|
||||
|
||||
2. **Create a Renderer Script**:
|
||||
Make a new file, `render.js`, at the root of your project.
|
||||
|
||||
```javascript
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const React = require('react');
|
||||
const ReactDOMServer = require('react-dom/server');
|
||||
const App = require('./src/App').default;
|
||||
|
||||
const html = ReactDOMServer.renderToStaticMarkup(
|
||||
React.createElement(App)
|
||||
);
|
||||
|
||||
const fullHtml = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>My Static Site</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root">${html}</div>
|
||||
</body>
|
||||
</html>`;
|
||||
|
||||
fs.writeFileSync(
|
||||
path.resolve(__dirname, 'build', 'index.html'),
|
||||
fullHtml,
|
||||
'utf8'
|
||||
);
|
||||
```
|
||||
|
||||
3. **Modify Your App Component**:
|
||||
Ensure that your React components are defined in a way that makes them easily rendered to static HTML. For instance, if you have any runtime-specific logic, you may need to adjust it.
|
||||
|
||||
4. **Run the Renderer Script**:
|
||||
Run the script to generate the static HTML file.
|
||||
|
||||
```sh
|
||||
node render.js
|
||||
```
|
||||
|
||||
5. **View the Output**:
|
||||
Check the `build` directory for your `index.html`. This file is now pure HTML
|
||||
and can be deployed as a static site.
|
||||
|
||||
### Method 2: Using Next.js for Static Site Generation
|
||||
|
||||
Using Next.js, a React framework, it is easier to pre-render static HTML:
|
||||
|
||||
1. **Create a Next.js App**:
|
||||
|
||||
```sh
|
||||
npx create-next-app my-static-site
|
||||
cd my-static-site
|
||||
```
|
||||
|
||||
2. **Set Up Static Generation**:
|
||||
By default, pages in Next.js will be pre-rendered as static HTML. Define your pages in the `pages` directory.
|
||||
|
||||
3. **Create Pages**:
|
||||
Example of a simple index page in `pages/index.js`:
|
||||
|
||||
```jsx
|
||||
const Home = () => {
|
||||
return (
|
||||
<div>
|
||||
<h1>Welcome to my Static Site</h1>
|
||||
<p>This is a static HTML page generated by Next.js.</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Home;
|
||||
```
|
||||
|
||||
4. **Build the Site**:
|
||||
Build your site for production:
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
npm run export
|
||||
```
|
||||
|
||||
5. **View the Output**:
|
||||
The HTML files will be in the `out` directory, which can be deployed statically.
|
||||
|
||||
### Method 3: Using Gatsby for Static Site Generation
|
||||
|
||||
1. **Create a Gatsby Site**:
|
||||
|
||||
```sh
|
||||
npx gatsby new my-static-site
|
||||
cd my-static-site
|
||||
```
|
||||
|
||||
2. **Create Pages**:
|
||||
Define your pages in the `src/pages` directory. An example `index.js` file:
|
||||
|
||||
```jsx
|
||||
import React from "react";
|
||||
|
||||
const Home = () => (
|
||||
<div>
|
||||
<h1>Welcome to my Static Site</h1>
|
||||
<p>This is a static HTML page generated by Gatsby.</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default Home;
|
||||
```
|
||||
|
||||
3. **Build the Site**:
|
||||
Build your Gatsby site:
|
||||
|
||||
```sh
|
||||
npm run build
|
||||
```
|
||||
|
||||
4. **View the Output**:
|
||||
The generated HTML files are in the `public` directory.
|
||||
|
||||
### Conclusion
|
||||
You can choose an appropriate method based on your existing setup and requirements. Using frameworks like Next.js or Gatsby, which are designed for static site generation, generally makes the process simpler and more efficient.
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
basics
|
||||
|
||||
**links**
|
||||
https://github.com/stolinski/svelte-5-course
|
||||
https://youtu.be/8DQailPy3q8 : Svelte 5 Basics - Complete Svelte 5 Course for Beginners
|
||||
https://youtu.be/j3aliHghr3E : Data Flow in Svelte 5 | How to fetch & pass data from the backend to the frontend in SvelteKit
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
extras
|
||||
|
||||
about effect rune
|
||||
|
||||
```js
|
||||
<script>
|
||||
let count = $state(0);
|
||||
let doubled = $derived(count * 2);
|
||||
let triggerValue = $state('initial');
|
||||
|
||||
// This runs whenever any reactive value used inside changes
|
||||
$effect(() => {
|
||||
console.log('Effect ran:', count, doubled);
|
||||
});
|
||||
|
||||
// This will only run when triggerValue changes
|
||||
$effect(() => {
|
||||
console.log('Triggered effect:', triggerValue);
|
||||
// You can use other values here, but it won't re-run when they change
|
||||
}).with(triggerValue);
|
||||
</script>
|
||||
```
|
||||
13
joplin notion extension/Web Development/React/vite.md
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
vite
|
||||
https://vitejs.dev/guide/
|
||||
|
||||
- `npm create vite@latest`
|
||||
```
|
||||
cd my-project
|
||||
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
or
|
||||
`npm create vite@latest my-vue-app --- --template vue`
|
||||
other templates are vanilla, vanilla-ts, vue, vue-ts, react, react-ts, preact, preact-ts, lit, lit-ts, svelte, svelte-ts, solid, solid-ts, qwik, qwik-ts.
|
||||
58
joplin notion extension/Web Development/heroku/Bohr io.md
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
Bohr io
|
||||
|
||||
|
||||
|
||||
[express-template-main.zip](../../../_resources/express-template-main.zip)
|
||||
|
||||
|
||||
|
||||
server.ts
|
||||
|
||||
```jsx
|
||||
import express, { Response, Request } from "express";
|
||||
|
||||
var app = express();
|
||||
|
||||
const users = [
|
||||
{ id: 1, name: "Lucas" },
|
||||
{ id: 2, name: "Eric" },
|
||||
{ id: 3, name: "Ana" },
|
||||
];
|
||||
|
||||
|
||||
app.get("/", function (req: Request, res: Response) {
|
||||
res.send("Bohr Express template");
|
||||
});
|
||||
|
||||
app.get("/users", function (req: Request, res: Response) {
|
||||
res.send(users);
|
||||
});
|
||||
|
||||
app.get("/users/:userId", function (req: Request, res: Response) {
|
||||
const user = users.find((user) => user.id === parseInt(req.params.userId));
|
||||
res.send(user);
|
||||
});
|
||||
|
||||
if (!module.parent) {
|
||||
app.listen(3000);
|
||||
console.log("Express started on port 3000");
|
||||
}
|
||||
|
||||
export default app;
|
||||
```
|
||||
|
||||
index.ts
|
||||
|
||||
```jsx
|
||||
const serverless = require('serverless-http');
|
||||
import app from './server';
|
||||
|
||||
module.exports.handler = serverless(app);
|
||||
```
|
||||
|
||||
|
||||
Commands
|
||||
|
||||
|
||||

|
||||
|
||||
61
joplin notion extension/Web Development/heroku/Extras.md
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
Extras
|
||||
|
||||
dns
|
||||
- adguard
|
||||
for mobile
|
||||
`dns.adguard.com`
|
||||
for browser
|
||||
`https://dns.adguard.com/dns-query`
|
||||
for linux
|
||||
https://adguard-dns.io/kb/private-dns/connect-devices/mobile-and-desktop/linux/#configure-manually-on-debian-linked-ip-or-dedicated-ip-required
|
||||
`94.140.14.49 94.140.14.59;`
|
||||
|
||||
- nextdns
|
||||
in browser
|
||||
`https://nextdns.io` (didnt work)
|
||||
- cloudflare
|
||||
for mobile
|
||||
`1dot1dot1dot1.cloudflare-dns.com` or `one.one.one.one`
|
||||
system
|
||||
`1.1.1.1 2606:4700:4700::1111 1.0.0.1 2606:4700:4700::1001`
|
||||
browser
|
||||
`https://cloudflare-dns.com/dns-query`
|
||||
|
||||
- quad9
|
||||
for mobile
|
||||
`dns.quad9.net`
|
||||
browser
|
||||
`https://dns.quad9.net/dns-query`
|
||||
system
|
||||
`9.9.9.9 149.112.112.112`
|
||||
- google
|
||||
system
|
||||
`8.8.8.8 8.8.4.4`
|
||||
mobile
|
||||
`dns.google`
|
||||
browser
|
||||
`https://dns.google`
|
||||
|
||||
adding dns in system
|
||||
`nano /etc/systemd/resolved.conf`
|
||||
then
|
||||
```ini
|
||||
DNS=94.140.14.14 94.140.15.15 2a10:50c0::ad1:ff 2a10:50c0::ad2:ff
|
||||
FallbackDNS=1.1.1.1
|
||||
Domains=~.
|
||||
DNSOverTLS=yes
|
||||
```
|
||||
then
|
||||
`sudo systemctl restart systemd-resolved`
|
||||
|
||||
for jiotv
|
||||
for this hidden settings, applications to settings(android one not jio one)
|
||||
If your Jio STB allows you to change IP settings (this varies depending on the specific firmware version Jio has pushed to your box), you can point it directly to a private ad-blocking DNS.
|
||||
1. Go to Settings > Network & Internet on your Jio STB.
|
||||
2. Select your connected Wi-Fi network or Ethernet connection.
|
||||
3. Look for IP Settings and change it from DHCP to Static.
|
||||
4. Keep the IP address, Gateway, and Network Prefix Length exactly as they are pre-filled (just click next through them).
|
||||
5. When you reach DNS 1 and DNS 2, enter public ad-blocking servers:
|
||||
• AdGuard DNS 1: 94.140.14.14
|
||||
• AdGuard DNS 2: 94.140.15.15
|
||||
6. Save and restart the STB
|
||||
110
joplin notion extension/Web Development/heroku/domains.md
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
domains
|
||||
|
||||
Providers
|
||||
- tk domains r free : http://www.dot.cf/en/index.html?lang=en
|
||||
- http://www.dot.cf/en/index.html?lang=en
|
||||
- freenom (no longer available)
|
||||
ml is the country tld of mali Mali leased it to freenom and lease is expired
|
||||
- https://freedns.afraid.org
|
||||
- noip
|
||||
- https://nic.eu.org/
|
||||
- freenom : doesnt work
|
||||
- https://freedomain.one/
|
||||
- https://dash.domain.digitalplat.org/auth/register
|
||||
- https://desec.io/signup : for residential ip and needs ip to be changed
|
||||
- https://www.duckdns.org : login with github/google
|
||||
- https://github.com/abint7/free-domains?tab=readme-ov-file
|
||||
|
||||
- Exposing localhost
|
||||
|
||||
ngrok (ngrok http 80)
|
||||
serveo (no signup required) : https://serveo.net/ (sometimes it dont work)
|
||||
PageKite
|
||||
localtunnel
|
||||
https://github.com/openziti/zrok : can self host it too
|
||||
boringproxy
|
||||
BrowserStack
|
||||
https://localhost.run/
|
||||
https://loophole.cloud/ (for http services, provides https domain too) (./loophole http 3006)
|
||||
https://www.youtube.com/watch?v=QddDX5x7Iz4 : for ssh using ngrok
|
||||
(just type ngrok tcp 22) to make ssh accessible to public internet, limited to 1 connection
|
||||
- Checking pot forwarding
|
||||
portchecker.io
|
||||
- Handling blocked port forwarding
|
||||
https://portmap.io/register (Sounds promising) (tried but not working :( )
|
||||
https://www.saashub.com/portmap-io-alternatives
|
||||
using a vpn
|
||||
https://www.reddit.com/r/india/comments/dwrn33/port_forwarding_in_jio_fiber_router/
|
||||
https://tailscale.com/kb/1223/funnel/ : tailscale (can expose http to internet upto 3 users but cant tls/ssh)
|
||||
zerotier (wont expose to whole internet but useful for playing minecraft and all)
|
||||
It doesnt port forward but what it does it creating virtual local area netwrok as people r using same wifi who is using zerotier app anywhere in world. Somene in usa, russia, china can all be part of virtual LAN if using this app
|
||||
https://www.reddit.com/r/HomeNetworking/comments/18f9z9y/my_isp_doesnt_allow_port_forwarding_what_are_my/
|
||||
|
||||
|
||||
|
||||
### more for exposing localhost
|
||||
|
||||
**from llm**
|
||||
Yes, there are several services similar to **ngrok** that create secure tunnels from your localhost to the public internet and provide **static/fixed domains** (either branded subdomains like `yourname.service.com` or full custom domains you own).
|
||||
|
||||
ngrok's free tier gives only a random or one reserved static subdomain (with limitations like warnings), while static/persistent ones are mostly paid. Many alternatives offer better free tiers or lower-cost static options, especially in 2026.
|
||||
|
||||
Here's a breakdown of popular ones that support **static domains** (persistent URLs that don't change on restart):
|
||||
|
||||
### Free or Very Low-Cost with Static Domain Support
|
||||
- **Cloudflare Tunnel** (cloudflared)
|
||||
Completely **free** (no bandwidth limits for basic use).
|
||||
Use your own domain (e.g., `matrix.yourdomain.com`) for a fixed URL — requires adding your domain to Cloudflare (free).
|
||||
No random changes; the tunnel stays on the same hostname as long as it's running.
|
||||
Great for Matrix/Synapse (HTTPS by default, no interstitial pages).
|
||||
Setup is a bit more involved than ngrok (dashboard + CLI), but it's reliable and production-grade.
|
||||
|
||||
- **LocalXpose**
|
||||
Free tier: 2 active HTTP tunnels with **persistent subdomains** (e.g., your-chosen-name.localxpose.io — static on free).
|
||||
Paid starts low (~$6-8/mo) for more tunnels, custom domains, UDP/TCP, unlimited bandwidth.
|
||||
Often praised as a direct ngrok replacement with fewer restrictions.
|
||||
|
||||
- **Pinggy**
|
||||
Free tier available (no signup for basic).
|
||||
Supports **persistent subdomains** and custom domains (even on lower plans).
|
||||
Paid from ~$2.5-3/mo for full features like custom domains and persistent ports.
|
||||
Very cheap and easy (SSH-based, no install sometimes).
|
||||
|
||||
- **InstaTunnel** (mentioned a lot in 2026 comparisons)
|
||||
Free plan includes **persistent custom subdomains** (choose your own like `sagar.instatunnel.com` — no random changes).
|
||||
Much more generous free tier than ngrok (longer sessions, no warnings).
|
||||
Paid ~$5/mo for advanced stuff.
|
||||
Positioned as a "better free ngrok" for daily dev use.
|
||||
|
||||
- **Playit.gg**
|
||||
Free tier with up to 4 tunnels (TCP/UDP focus, good for games but works for HTTP).
|
||||
**Static/custom domains** on paid (~$3/mo).
|
||||
Simple for basic needs.
|
||||
|
||||
- **Zrok** (open-source, based on OpenZiti)
|
||||
Free/self-hosted option — fully unlimited, supports static if you self-host or use their service.
|
||||
Public sharing with persistent links possible.
|
||||
|
||||
### Other Notable Ones
|
||||
- **Localtonet** — Often ranked top in 2026 lists; free tier + cheap paid (~$2/tunnel/mo) with custom domains, UDP, unlimited bandwidth.
|
||||
- **Tailscale Funnel** — Free for personal use; static via your Tailscale setup (more VPN-like, but exposes services publicly with fixed names).
|
||||
- **localhost.run** or **Tunnelmole** — Free/basic, but custom/static domains usually paid/low-cost.
|
||||
|
||||
### Quick Comparison Table (Focus on Static Domain)
|
||||
|
||||
| Service | Free Static/Subdomain? | Custom Domain (Your Own)? | Paid Starts At | Notes for Synapse/Matrix Use |
|
||||
|----------------------|---------------------------------|----------------------------|----------------|-----------------------------------------------|
|
||||
| ngrok | 1 reserved (free), but limited | Paid only | ~$8-10/mo | Warnings on free; paid for stable |
|
||||
| Cloudflare Tunnel | Yes (with your domain) | Yes (free) | Free | Best free fixed domain; no warnings |
|
||||
| LocalXpose | Yes (persistent subdomains) | Yes | ~$6-8/mo | Generous free; good alternative |
|
||||
| Pinggy | Limited free; yes on paid | Yes | ~$2.5-3/mo | Cheap & easy |
|
||||
| InstaTunnel | Yes (custom subdomains free) | Likely paid | ~$5/mo | Very dev-friendly free tier in 2026 |
|
||||
| Localtonet | Basic free | Yes | ~$2/mo | UDP support, highly rated |
|
||||
|
||||
For your Matrix Synapse setup (since you have a domain already), **Cloudflare Tunnel** is still one of the strongest free options for a truly static, professional URL without paying extra. If you want something simpler with a free branded static subdomain (no need to manage DNS), try **InstaTunnel** or **LocalXpose** first — they're closer to ngrok's "just run a command" feel.
|
||||
|
||||
Which one sounds most appealing (e.g., completely free with your domain, or easiest with branded static subdomain)? I can give exact setup steps for it!
|
||||
|
||||
- Port forwarding
|
||||
By default, routers can transmit any outgoing traffic but for any traffic from external device to router ie inbound traffic, port forwarding needs to be alloweed
|
||||
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
- Links
|
||||
https://free-for.dev/#/
|
||||
https://github.com/dalisoft/awesome-hosting
|
||||
|
||||
|
||||
nextjs
|
||||
https://wiki.helionet.org/tutorials/node.js/next.js
|
||||
for upto next13 not next14 as node 18 is required
|
||||
https://docs.render.com/deploy-nextjs-app : for next14 too
|
||||
|
||||
### hosting plain text
|
||||
pastecord
|
||||
https://github.com/bokub/nopaste https://nopaste.boris.sh/
|
||||
[nopaste-master.zip](../../../_resources/nopaste-master.zip)
|
||||
|
||||
|
||||
hastebin (api but have limits like content deleted after 30 days)
|
||||
pastecode
|
||||
pastebin https://pastebin.com/doc_api
|
||||
https://text.is/
|
||||
https://microbin.eu/ (open source, needs to be self hosted)
|
||||
https://badcord.ct8.pl/ (everything is public and indexed, bad for privacy)
|
||||
https://rlim.com (like text.is and have more feature)
|
||||
https://lesma.eu (have api but 30 days validity)
|
||||
https://github.com/davidmerfield/blot (open source, self hosted. it can host files)
|
||||
https://justpaste.it : for html preview too for images atleast. no api
|
||||
rentry.co https://www.npmjs.com/package/rentry-pastebin
|
||||
https://textbin.net/
|
||||
https://paste.ee
|
||||
https://sntry.cc/
|
||||
https://codeberg.org/SentryTwo/bundles : Source code for rentry, text.is, rlim.com, sntry.cc
|
||||
(It uses bun which is alternative of nodejs)
|
||||
https://sentrytwo.com/
|
||||
[bundles-master.zip](../../../_resources/bundles-master.zip)
|
||||
https://github.com/hedgedoc/hedgedoc
|
||||
|
||||
|
||||
|
||||
Nodejs hosting with full container
|
||||
https://github.com/DmitryScaletta/free-heroku-alternatives
|
||||
- render (no persistent file storage)
|
||||
- heliohost : need to login once a month to keep it active
|
||||
- https://console.choreo.dev
|
||||
- https://www.lade.io/dashboard : have to install cli
|
||||
- zeabur : 24 hr temporary deployment
|
||||
- glitch (need to upload each file individually and code will be public too) : closed
|
||||
- koyeb (1 web service free)
|
||||
- https://basementhost.net/ : free vps (not checked yet ) bad deal wih exchange though
|
||||
- linode : 5$/month , cheap vps
|
||||
- https://cloudjiffy.com/pricing/ : cheap and accept upi too, indian one
|
||||
- oracle cloud free tier vps : free forever
|
||||
- netcup : cheap vps
|
||||
- Racknerd : cheap vps 15$/yr
|
||||
- https://www.vultr.com/pricing/ : starts from 2.5$/month , need to submit 10 dollar atleast
|
||||
- https://www.nearlyfreespeech.net/ : starting from 0.25$
|
||||
warning : not anonymised and need govt id to create account
|
||||
- https://northflank.com/pricing (require credit card )
|
||||
- https://www.cloudsigma.com/ : starts from 3$/month and have prepaid
|
||||
- ultravps , hertzner : hertzner provoides good specs for 4.2$/month way better than DO and vultr
|
||||
- https://alphavps.com/cheap-vps.html
|
||||
|
||||
|
||||
other hosting platforms
|
||||
- https://www.shuttle.rs/ : for rust
|
||||
- pythonanywhere : for python
|
||||
|
||||
|
||||
|
||||
vps
|
||||
- ovh : sometimes they have a good deal
|
||||
- https://lowendstock.com/ :
|
||||
-
|
||||
|
||||
https://wheretohostmy.app/services : wjer to host my web
|
||||
|
||||
[Web Hosting (10_26_2023 7_15_20 PM).html](../../../_resources/Web%20Hosting%20%2810_26_2023%207_15_20%20PM%29.html)
|
||||
|
||||
|
||||
|
||||
|
||||
mysql : planetscale,infinityFree, x10hosting, freehosting.com, bytehost
|
||||
**AwardSpace**: AwardSpace provides free web hosting with remote MySQL access. They offer both free and paid hosting plans.
|
||||
|
||||
**InfinityFree**: Although they do not offer remote MySQL access for free, they provide low-cost hosting options with this feature.
|
||||
|
||||
**000WebHost**: 000WebHost offers free web hosting with remote MySQL access as part of their free plan.
|
||||
|
||||
**ByetHost**: ByetHost provides free hosting with remote MySQL database support.
|
||||
|
||||
infinityfree, 000webhost, freehosting.com, byethost all needs premium for remote mysql
|
||||
x10hosting : blocked in my country
|
||||
freehosting.com : requires my own domain
|
||||
freehostia : requires credit card
|
||||
gooogiehost : requires credit card
|
||||
|
||||
**Databases**
|
||||
Remote mysql
|
||||
1. https://tidbcloud.com/
|
||||
2. planetscale
|
||||
3. https://freedb.tech/
|
||||
4. https://www.freesqldatabase.com : requires interacting with it every week.
|
||||
5. https://filess.io (10 mb, 2 databases, mongo, mysql and postgresql)
|
||||
6. https://www.freemysqlhosting.ne (5 mb free only)
|
||||
7. https://db4free.net/signup.php (for testing only)
|
||||
8. Or use json and store in gist github
|
||||
|
||||
|
||||
mongodb atlas : mongodb
|
||||
https://studio3t.com/knowledge-base/articles/cheap-free-mongodb-hosting/, clever cloud : mongodb
|
||||
postgres : cockroachDB
|
||||
https://gigalixir.com/ : postgresql
|
||||
https://www.koyeb.com/blog/top-postgresql-database-free-tiers-in-2024
|
||||
Koyeb : postgresql (may suspend yur account if not provided phone number)
|
||||
supabase (project pause 1 wek of inactivity, cron job required to stop it)
|
||||
neon (connection closed after 5min of inactivity, reconnecing it every few min will fix it)
|
||||
aiven (for mysql and postgresql)
|
||||
sqlite : https://turso.tech/
|
||||
https://gist.github.com/bmaupin/0ce79806467804fdbbf8761970511b8c
|
||||
https://upstash.com : redis
|
||||
|
||||
- Cloud services
|
||||
anonfiles.net : file sharing(file will expire)
|
||||
https://imgbb.com/ : image sharing
|
||||
|
||||
|
||||
- Markdown hosting
|
||||
https://www.duckdocs.com
|
||||
https://about.readthedocs.com/pricing/ : for documentation
|
||||
https://www.reddit.com/r/webdev/comments/z01c7j/is_there_anyway_to_host_markdown_files_online/
|
||||
|
||||
- Web services
|
||||
1. Heliohost : panel(max 10 sites and frustrating to use but very powerful)
|
||||
https://www.youtube.com/watch?v=movy0X152G0
|
||||
https://files.sdrive.app/3f05fbff-162c-48d6-9a5a-c3b60c6ddbd6.mp4
|
||||
2. https://qoddi.com (now requires credit card)
|
||||
3. https://bohr.io/ : for projetcts
|
||||
4. https://mdbgo.com/ : for testing only. everything will be destroyed after 2 weeks
|
||||
5. serv00 : https://docs.serv00.com/WWW/ : remote server doesnt work
|
||||
6. hop : like replit but 30 days trial only
|
||||
7. https://my.domcloud.co : 3 projects, 2gb bandwidth, skiff and proton not allowed, need to be log in every 60 days to retain account
|
||||
https://domcloud.co/docs/intro
|
||||
8. https://www.napkin.io/ : like deta, its FAAS(Function as a service) and timeout is 15s
|
||||
https://docs.napkin.io
|
||||
|
||||
back4app (not anymore only for its own key-value database)
|
||||
glitch
|
||||
render
|
||||
adaptable (now paid)
|
||||
cyclic (shutdown)
|
||||
deta (shutdown)
|
||||
higgingface (ai based maybe for nodejs)
|
||||
vercel : not easy though
|
||||
cloudflare workers (no expressjs)
|
||||
deno dceploy (close to node)
|
||||
zeet.co (first 3 projects r free) (needs separate cluster)
|
||||
trydome (needs credit card to deploy)
|
||||
|
||||
- static sites
|
||||
1. https://kinsta.com
|
||||
2. https://surge.sh/
|
||||
3. https://dappling.network/ : decentralized
|
||||
4. https://freeflarum.com/ : for forums only
|
||||
5. https://dash.deno.com/
|
||||
16
joplin notion extension/Web Development/heroku/supabase.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
supabase
|
||||
|
||||
```js
|
||||
|
||||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const supabaseUrl = 'https://aywqqxustyxxcztijohc.supabase.co'
|
||||
const supabaseKey = process.env.SUPABASE_KEY
|
||||
const supabase = createClient(supabaseUrl, supabaseKey)
|
||||
```
|
||||
- Configurations
|
||||
In project settings > configurations section > Database
|
||||
`https://supabase.com/dashboard/project/[project ref]/settings/database`
|
||||
With uri
|
||||
`postgres://postgres.[project_ref]:[YOUR-PASSWORD]@<host_name>:5432/postgres`
|
||||
Their database name is postgres and username is postgress along with project reference
|
||||
9
joplin notion extension/Web Development/heroku/vps.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
vps
|
||||
|
||||
todo
|
||||
1. vpn using wiregiard or openvpn
|
||||
2. proxy server
|
||||
3. gitea
|
||||
4. chat server like matrix, irc chat
|
||||
5. configure database like mongodb, mysql, psql
|
||||
6. web scraper
|
||||
87
joplin notion extension/Web Development/nodejs/Basics.md
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
Basics
|
||||
|
||||
- express static public
|
||||
```js
|
||||
const express = require("express");
|
||||
const fetch = require("node-fetch");
|
||||
const cors = require("cors");
|
||||
const PORT=process.env.PORT || 8080;
|
||||
const app = express();
|
||||
app.use(express.static(__dirname + "/public"));
|
||||
|
||||
app.use(express.json());
|
||||
const corsOptions = {
|
||||
origin: 'http://example.com',
|
||||
credentials: true,
|
||||
};
|
||||
|
||||
app.use(cors(corsOptions));
|
||||
|
||||
|
||||
const server = app.listen(PORT, () => {
|
||||
console.log(`app is running on port ${PORT}`);
|
||||
|
||||
});
|
||||
|
||||
```
|
||||
- asynchronous vs (multithreading, single threaded)
|
||||
So when an application is single threaded, it can only consume one logical cpu execution context at a time (one thread)
|
||||
This means the logic happens step-by-step (can only be interrupted by the cpu scheduler)
|
||||
|
||||
When an app is multithreaded, it creates child processes via forking or process ownership that it communicates to via shared memory or messaging. Whether the multiple threads perform the same work is up to the design of the application
|
||||
|
||||
asynchronous single threaded : It can perform multiple tasks, not at the same time though.
|
||||
Node's async functionality just lets blocks of code wait for preconditions before it runs -- it's not truly async with other code
|
||||
|
||||
for simultaneoulsy request sometimes
|
||||
In NodeJS, a single instance can use one thread, unless it forks or spawns a worker.
|
||||
Most node webservers use forking, where they effectively spawn one process per logical thread on the host server. They randomly get traffic by a special "port sharing" feature of Node itself -- which is managed by the cluster module IIRC
|
||||
- express get with query
|
||||
```js
|
||||
app.get("/getaudio", async (req, res) => {
|
||||
const queryObj = req.query;
|
||||
console.log("queryobj: ", queryObj);
|
||||
|
||||
const { url, title, q } = queryObj;
|
||||
}
|
||||
}
|
||||
```
|
||||
- express get with params
|
||||
```js
|
||||
app.get('/books/:id', (req,res)=>{
|
||||
const {id}=req.params
|
||||
} )
|
||||
```
|
||||
- express res object
|
||||
- headers
|
||||
`res.setHeaders` - calls the native Node.js method
|
||||
`res.set` - sets headers
|
||||
`res.headers` - an alias to res.set
|
||||
|
||||
```js
|
||||
res.set('Content-Type', 'text/plain');
|
||||
res.set({
|
||||
'Content-Type': 'text/plain',
|
||||
'Content-Length': '123',
|
||||
'ETag': '12345'
|
||||
})
|
||||
|
||||
res.header(field, [value])
|
||||
|
||||
res.setHeader(
|
||||
"Access-Control-Allow-Methods",
|
||||
"GET,OPTIONS,PATCH,DELETE,POST,PUT"
|
||||
);
|
||||
|
||||
```
|
||||
- middleware
|
||||
https://www.geeksforgeeks.org/middleware-in-express-js/
|
||||
|
||||
|
||||
|
||||
to only install production dependencies use
|
||||
`npm install --omit=dev`
|
||||
for only dev dependenciues
|
||||
`npm install --only=dev`
|
||||
for both
|
||||
`npm i`
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
Downloading and transferring blobs
|
||||
|
||||
```js
|
||||
fetch(url)
|
||||
.then((res) => res.blob())
|
||||
.then(async (blob) => {
|
||||
console.log("got blob");
|
||||
console.log("Took " + (Date.now() - initialTime) / 1000 + "s");
|
||||
// const title = "video";
|
||||
|
||||
// const file = await res.blob();
|
||||
const arrayBuffer = await blob.arrayBuffer();
|
||||
const buffer = Buffer.from(arrayBuffer);
|
||||
|
||||
// console.log("bytelength: ", buffer.byteLength());
|
||||
// const arrayByte = new Uint8Array(arrayBuffer);
|
||||
|
||||
res.writeHead(200, {
|
||||
"content-type": "application/octet-stream",
|
||||
});
|
||||
|
||||
console.log("converted to buffer");
|
||||
res.write(buffer);
|
||||
// const writeStream = fs.createWriteStream(arrayByte);
|
||||
|
||||
// res.sendFile(buffer);
|
||||
res.end();
|
||||
// const buffer = Buffer.from(file, "binary");
|
||||
// file.pipe(fs.createWriteStream(`${title}.mp4`));
|
||||
// fs.writeFileSync(`${title}12.mp4`, buffer);
|
||||
})
|
||||
.catch((err) => console.log(err));
|
||||
```
|
||||
175
joplin notion extension/Web Development/nodejs/Extras.md
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
Extras
|
||||
|
||||
- https://stackoverflow.com/questions/36022926/what-do-the-save-flags-do-with-npm-install
|
||||
`npm i <package_name> --save` and `npm i <package_name> ` are same now and they also update dependencies of package too. to not update dependencies of package use `npm i <package_name> --no-save`
|
||||
|
||||
- nvm(Node version manager)
|
||||
`curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash`
|
||||
|
||||
`nvm ls-remote` : for getting list of available versions which can be downloaded
|
||||
`nvm list` : for getting list of downloaded versions of node
|
||||
`nvm install 14.0.0` : for downloading and installing version 14.0.0
|
||||
`nvm use 14.0.0` : switching to version 14.0.0
|
||||
`nvm use system`: switching to version when nodejs first installed
|
||||
`nvm alias default 18.0`: this will make 18 as default
|
||||
|
||||
- https://github.com/ishtms/learn-nodejs-hard-way (without installing other frameworks)
|
||||
- https://youtu.be/Nh-252u80F4 : get wifi password
|
||||
- Running nodejs in background
|
||||
https://sentrytwo.com/92df06609b
|
||||
- To avoid running sudo
|
||||
Why You Should Never Run "sudo npm"... https://www.youtube.com/watch?v=aFrR56sqC_A
|
||||
- **pm2**
|
||||
PM2 is a production process manager for Node.js applications with a built-in load balancer. It allows you to keep applications alive forever, to reload them without downtime and to facilitate common system admin tasks.
|
||||
install this npm package globally or locally.
|
||||
`npm i -g pm2`
|
||||
Using this we can start multiple node instances with single command. But first starting node application instances in background
|
||||
`pm2 start app.js --name app1` same as `node app.js` but in background
|
||||
to stop node instance use `pm2 stop app1`
|
||||
multiple node instance in file `ecosystem.config.js`
|
||||
```js
|
||||
module.exports = {
|
||||
apps: [
|
||||
{
|
||||
name: 'main',
|
||||
|
||||
script: 'index.js',
|
||||
watch: true,
|
||||
env: {
|
||||
NODE_ENV: 'production',
|
||||
PORT: 8081
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ytdownloadspace',
|
||||
script: '../ytDownloadSpace/app.js',
|
||||
watch: true,
|
||||
env: {
|
||||
NODE_ENV: 'production',
|
||||
PORT: 8080
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'ytdlApi',
|
||||
script: '../ytdlApi/app.js',
|
||||
watch: true,
|
||||
env: {
|
||||
NODE_ENV: 'production',
|
||||
PORT: 8083
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
```
|
||||
and fiannly when use
|
||||
`pm2 start ecosystem-config.js`.
|
||||
To stop all these started with this file use
|
||||
`pm2 stop ecosystem-config.js`
|
||||
To list processes use
|
||||
`pm2 list`
|
||||
- installing packages through repo link
|
||||
`npm i https://github.com/expressjs/express`
|
||||
https://www.pluralsight.com/resources/blog/guides/install-npm-packages-from-gitgithub
|
||||
|
||||
|
||||
- download a file with https and fs module
|
||||
```js
|
||||
const https = require("https"); // Use 'http' for non-HTTPS links
|
||||
const fs = require("fs");
|
||||
|
||||
const fileUrl =
|
||||
"https://cdn.discordapp.com/attachments/1473231612341915668/1473231989501853819/packages_sorted2.txt?ex=699575b5&is=69942435&hm=66884969a27901525409ff1e5400619ea5305667a130476b7982e041c55297e8&"; // Replace with your file URL
|
||||
const destinationPath = "./downloaded-file.txt"; // Replace with desired local path and filename
|
||||
|
||||
const file = fs.createWriteStream(destinationPath);
|
||||
|
||||
https
|
||||
.get(fileUrl, (response) => {
|
||||
// Check if the request was successful (status code 200)
|
||||
if (response.statusCode !== 200) {
|
||||
console.error(`Download failed, status code: ${response.statusCode}`);
|
||||
file.close(); // Close the write stream
|
||||
fs.unlink(destinationPath, () => {}); // Delete the partial file
|
||||
return;
|
||||
}
|
||||
|
||||
// Pipe the response stream to the file stream
|
||||
response.pipe(file);
|
||||
|
||||
// Event listener for when the download is complete
|
||||
file.on("finish", () => {
|
||||
file.close();
|
||||
console.log("Download Completed!");
|
||||
});
|
||||
})
|
||||
.on("error", (err) => {
|
||||
// Handle network errors
|
||||
fs.unlink(destinationPath, () => {}); // Delete the partial file on error
|
||||
console.error("Error during download:", err.message);
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
tips
|
||||
1. to prevent adding of installed packages in package.json use `--no-save` flag when installing packages. eg: `npm i --no-save sqlite3`
|
||||
|
||||
|
||||
|
||||
better-sqlite guide
|
||||
https://www.w3resource.com/sqlite/snippets/better-sqlite3.php
|
||||
[Comprehensive Guide to Better-SQLite3 (16_5_2026 5:48:16 am).html](../../../_resources/Comprehensive%20Guide%20to%20Better-SQLite3%20%2816_5_2026%205.html)
|
||||
for parameterized query, string concatenation using `||`
|
||||
```js
|
||||
selectQuery = `select * from ${songDataTableEnums.tablename}
|
||||
where ${songDataTableEnums.columns.songname} like ? || '%' or ${songDataTableEnums.columns.songname} like '% '|| ? || '%'
|
||||
or ${songDataTableEnums.columns.artist_name} like ? || '%' or ${songDataTableEnums.columns.artist_name} like '% '|| ? || '%'`;
|
||||
```
|
||||
|
||||
|
||||
|
||||
generate thumbnails of video
|
||||
```js
|
||||
const ffmpeg = require('fluent-ffmpeg');
|
||||
|
||||
ffmpeg('path/to/video.mp4')
|
||||
.screenshots({
|
||||
count: 1,
|
||||
timemarks: ['00:00:02'], // Capture at 2 seconds
|
||||
filename: 'thumbnail.png',
|
||||
folder: 'output/path/'
|
||||
});
|
||||
|
||||
```
|
||||
or
|
||||
```js
|
||||
ffmpeg('input.mp4')
|
||||
.screenshots({
|
||||
count: 3, // Number of screenshots to take
|
||||
timestamps: ['10%', '30sec', 60], // Locations: percentages, strings, or numbers (seconds)
|
||||
filename: 'thumbnail-at-%s-seconds.png', // %s inserts the timestamp
|
||||
folder: './output', // Destination directory
|
||||
size: '320x240' // Rescales output width x height
|
||||
})
|
||||
.on('end', () => {
|
||||
console.log('Screenshots taken successfully!');
|
||||
})
|
||||
.on('error', (err) => {
|
||||
console.error('An error occurred: ' + err.message);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
* count: Total number of images to generate. If timestamps is not provided, it automatically distributes screenshots evenly across the video duration.
|
||||
* timestamps: An array specifying exact positions to snapshot.
|
||||
* Numbers represent absolute seconds (e.g., 15).
|
||||
* Strings format time as HH:MM:SS.milli or specific counts (e.g., '00:01:20').
|
||||
* Percentages evaluate relative to video length (e.g., '50%').
|
||||
* folder: Path to the directory where files will save.
|
||||
* filename: Format for file naming. Use %s to interpolate the specific frame's timestamp or %i for the index sequence.
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
HTML parser
|
||||
|
||||
- jsdom
|
||||
It's an npm library that can take html as input and let you do things like document.querySelector on it inside of NodeJS without running a sandboxed browser instance
|
||||
- node-html-parser : like jsdom
|
||||
https://www.npmjs.com/package/node-html-parser
|
||||
eg
|
||||
```js
|
||||
import { parse } from 'node-html-parser';
|
||||
|
||||
const root = parse('<ul id="list"><li>Hello World</li></ul>');
|
||||
|
||||
console.log(root.firstChild.structure);
|
||||
// ul#list
|
||||
// li
|
||||
// #text
|
||||
|
||||
console.log(root.querySelector('#list'));
|
||||
// { tagName: 'ul',
|
||||
// rawAttrs: 'id="list"',
|
||||
// childNodes:
|
||||
// [ { tagName: 'li',
|
||||
// rawAttrs: '',
|
||||
// childNodes: [Object],
|
||||
// classNames: [] } ],
|
||||
// id: 'list',
|
||||
// classNames: [] }
|
||||
console.log(root.toString());
|
||||
// <ul id="list"><li>Hello World</li></ul>
|
||||
root.set_content('<li>Hello World</li>');
|
||||
root.toString(); // <li>Hello World</li>
|
||||
```
|
||||
4
joplin notion extension/Web Development/nodejs/Issues.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
- To clean cache
|
||||
`npm cache clean --force`
|
||||
`npm cache verify`
|
||||
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
bash commands in nodejs
|
||||
|
||||
```js
|
||||
const { exec } = require('child_process');
|
||||
const util = require('util');
|
||||
const execPromise = util.promisify(exec);
|
||||
|
||||
async function runCommand() {
|
||||
try {
|
||||
const { stdout, stderr } = await execPromise('echo "Hello from Bash!"');
|
||||
console.log(stdout);
|
||||
} catch (error) {
|
||||
console.error(`Error: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
runCommand();
|
||||
|
||||
```
|
||||
30
joplin notion extension/Web Development/nodejs/cloudfare.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
cloudfare
|
||||
|
||||
- using it for tunnel
|
||||
https://yewtu.be/watch?v=Dp5VcCmlKh4
|
||||
`cloudfared tunnel --url http://localhost:8080`
|
||||
|
||||
- deploy nodejs app
|
||||
> it doesn't uses nodejs engine
|
||||
<https://developers.cloudflare.com/workers/runtime-apis/nodejs/>
|
||||
> express module isn't supported
|
||||
<https://hono.dev/> or <https://github.com/kwhitley/itty-router>
|
||||
> it don't give access to file system
|
||||
<https://www.cloudflare.com/developer-platform/r2/>
|
||||
> It's for basic things and simple requests
|
||||
No, you just have to build your app a bit differently
|
||||
- Example
|
||||
- cors-anywhere
|
||||
https://github.com/Zibri/cloudflare-cors-anywhere
|
||||
[cloudflare-cors-anywhere-master.zip](../../../_resources/cloudflare-cors-anywhere-master.zip)
|
||||
- cloudflare workers
|
||||
Use wrangler by installing it via npm then
|
||||
login with
|
||||
`wrangler login`
|
||||
if worker name is test then
|
||||
`wrangler init --from-dash test`
|
||||
Then finally deploy with
|
||||
`wrangler deploy` or `wrangler publish`
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
curl relation
|
||||
|
||||
- `curl -F "reqtype=fileupload" -F "userhash=####" -F "fileToUpload=@cutie.png" https://catbox.moe/user/api.php`
|
||||
Converting to node-fetch
|
||||
```js
|
||||
import fetch, { FormData, fileFromSync } from 'node-fetch';
|
||||
|
||||
const form = new FormData();
|
||||
form.append('reqtype', 'fileupload');
|
||||
form.append('userhash', '####');
|
||||
form.append('fileToUpload', fileFromSync('cutie.png'));
|
||||
|
||||
fetch('https://catbox.moe/user/api.php', {
|
||||
method: 'POST',
|
||||
body: form
|
||||
});
|
||||
```
|
||||
|
||||
Converting to axios
|
||||
```js
|
||||
import axios from 'axios';
|
||||
import FormData from 'form-data';
|
||||
import * as fs from 'fs';
|
||||
|
||||
const form = new FormData();
|
||||
form.append('reqtype', 'fileupload');
|
||||
form.append('userhash', '####');
|
||||
form.append('fileToUpload', fs.readFileSync('cutie.png'), 'cutie.png');
|
||||
|
||||
const response = await axios.post(
|
||||
'https://catbox.moe/user/api.php',
|
||||
form,
|
||||
{
|
||||
headers: {
|
||||
...form.getHeaders()
|
||||
}
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
61
joplin notion extension/Web Development/nodejs/ejs.md
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
ejs
|
||||
|
||||
https://www.digitalocean.com/community/tutorials/how-to-use-ejs-to-template-your-node-application
|
||||

|
||||
|
||||
layouts
|
||||
use this for layouts https://www.npmjs.com/package/express-ejs-layouts
|
||||
|
||||
```js
|
||||
const express = require('express');
|
||||
const expressLayouts = require('express-ejs-layouts');
|
||||
const app = express();
|
||||
|
||||
// Set EJS as the view engine
|
||||
app.set('view engine', 'ejs');
|
||||
|
||||
// Use the layouts middleware
|
||||
app.use(expressLayouts);
|
||||
|
||||
// Optional: Define a default layout file
|
||||
app.set('layout', 'layouts/layout');
|
||||
|
||||
```
|
||||
|
||||
layout at `views/layouts/layout.ejs`
|
||||
```html
|
||||
...
|
||||
<body>
|
||||
<main>
|
||||
<!-- Individual page content is injected here -->
|
||||
<%- body %>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
|
||||
```
|
||||
|
||||
view at `views/index.ejs`
|
||||
```html
|
||||
<h1>Welcome to my Homepage!</h1>
|
||||
<p>This is the main content of the home page.</p>
|
||||
|
||||
```
|
||||
|
||||
for custom layout
|
||||
```js
|
||||
app.get('/admin', (req, res) => {
|
||||
res.render('admin-dashboard', { layout: 'layouts/admin-layout' });
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
when using variable which might be undefined this is safest way to do it
|
||||
|
||||
```html
|
||||
<% if( typeof keyword!=='undefined' && keyword ){ %>
|
||||
<br>
|
||||
<% } %>
|
||||
```
|
||||
|
|
@ -0,0 +1,470 @@
|
|||
file split and merge (express and multer)
|
||||
|
||||
frontEnd
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<input id="fileInput" type="file" name="" id="" multiple ><br>
|
||||
<button onclick="submit()" id="submit">Submit</button>
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
js
|
||||
```jsx
|
||||
const fileEle=document.querySelector("#fileInput")
|
||||
const sliceSize=10*1024*1024 // 10MB
|
||||
|
||||
const promiseSetTimeOut = (time) => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, time);
|
||||
});
|
||||
};
|
||||
|
||||
const submitIndividual=async(file,index,total)=>{
|
||||
const fileSize=file.size
|
||||
const fileName=file.name
|
||||
|
||||
console.log('file: ',file)
|
||||
|
||||
let start=0;
|
||||
let end=sliceSize
|
||||
|
||||
const filePieces=[]
|
||||
let i=0;
|
||||
while(end<=fileSize)
|
||||
{
|
||||
const chunk = file.slice(start,end)
|
||||
if(end==fileSize)
|
||||
{
|
||||
filePieces.push({pos: i,chunk,isEnd: true,fileName})
|
||||
}
|
||||
else{
|
||||
filePieces.push({pos: i,chunk,isEnd: false})
|
||||
}
|
||||
|
||||
start=end
|
||||
end+=sliceSize
|
||||
i++
|
||||
}
|
||||
|
||||
if(start<fileSize)
|
||||
{
|
||||
const chunk = file.slice(start,fileSize)
|
||||
filePieces.push({pos: i,chunk,isEnd: true,fileName})
|
||||
i++
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
for(let filePiece of filePieces )
|
||||
{
|
||||
const form=new FormData()
|
||||
|
||||
// form.append('data',{pos: filePiece.pos,isEnd: filePiece.isEnd} )
|
||||
form.append('pos',filePiece.pos )
|
||||
form.append('isEnd',filePiece.isEnd)
|
||||
form.append('file',filePiece.chunk)
|
||||
form.append('fileName',filePiece.fileName)
|
||||
form.append('total',total)
|
||||
form.append('fileIndex',index)
|
||||
|
||||
const res=await fetch('/submit',{
|
||||
method: 'post',
|
||||
// headers: {
|
||||
// 'Content-Type': 'multipart/form-data'
|
||||
// },
|
||||
body: form
|
||||
})
|
||||
const data=await res.json()
|
||||
|
||||
await promiseSetTimeOut(2000)
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
console.log('file: ',file)
|
||||
console.log('filePieces: ',filePieces)
|
||||
|
||||
}
|
||||
|
||||
|
||||
const submit=async()=>{
|
||||
|
||||
for(let file of fileEle.files)
|
||||
{
|
||||
await submitIndividual(file,i,fileEle.files.length)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// const blob=new Blob(filePieces)
|
||||
// const a=document.createElement("a")
|
||||
// const link=URL.createObjectURL(blob)
|
||||
// a.href= link
|
||||
// a.download="something1"
|
||||
// a.click()
|
||||
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Nodejs
|
||||
```js
|
||||
const express=require('express')
|
||||
const fs=require('fs')
|
||||
const FormData= require('form-data')
|
||||
|
||||
const app=express()
|
||||
const PORT= process.env.PORT||8080
|
||||
|
||||
const multer=require('multer')
|
||||
const upload = multer({ dest: 'uploads/' });
|
||||
|
||||
// Define the fields you want to handle
|
||||
const fieldsToParse = [
|
||||
{ name: 'file', maxCount: 1 },
|
||||
{ name: 'pos', maxCount: 1 },
|
||||
{ name: 'isEnd', maxCount: 1 },
|
||||
{ name: 'fileName', maxCount: 1 },
|
||||
{ name: 'total', maxCount: 1 },
|
||||
{ name: 'fileIndex', maxCount: 1 },
|
||||
|
||||
];
|
||||
|
||||
|
||||
app.use(express.static(__dirname+'/front'))
|
||||
app.use(express.json());
|
||||
app.use(express.urlencoded({extended: true}) )
|
||||
|
||||
// 2d array. outer dimension containing files and inner dimension containing file pieces
|
||||
const fileObjs=[]
|
||||
let total=0
|
||||
|
||||
|
||||
|
||||
const getLast=(arr)=>{
|
||||
if(arr.length>0)
|
||||
return arr[arr.length-1]
|
||||
else{
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const mergeFile=()=>{
|
||||
// mergeFile will happen when only last filepiece is recieved so now
|
||||
// it will merge
|
||||
const filePieces=getLast(fileObjs)
|
||||
|
||||
const arrBuffer=[]
|
||||
let ogname=""
|
||||
for(let filePiece of filePieces)
|
||||
{
|
||||
const pieceData=fs.readFileSync(`uploads/${filePiece.name}`)
|
||||
fs.unlinkSync(`uploads/${filePiece.name}`)
|
||||
arrBuffer.push(pieceData)
|
||||
ogname=filePiece.ogName
|
||||
|
||||
|
||||
}
|
||||
|
||||
console.log('arrBuffer: ',arrBuffer)
|
||||
|
||||
const mergedFileBuffer=Buffer.concat(arrBuffer)
|
||||
fs.writeFileSync(`uploads/${ogname}`,mergedFileBuffer)
|
||||
}
|
||||
|
||||
app.post('/submit',upload.fields(fieldsToParse),(req,res)=>{
|
||||
|
||||
try{
|
||||
|
||||
if(total==0)
|
||||
{
|
||||
fileLinks.splice(0, fileLinks.length);
|
||||
}
|
||||
|
||||
const file = req.files['file'][0]; // Access the uploaded file
|
||||
const pos = req.body['pos']; // Access 'pos' field
|
||||
const isEnd = req.body['isEnd'];
|
||||
const fileName=req.body['fileName']
|
||||
total= Number(req.body['total'])
|
||||
const fileIndex=Number(req.body['fileIndex'])
|
||||
|
||||
// determining if current piece is beginning or not
|
||||
let isStart=false
|
||||
// const body=req.body
|
||||
// const file=req.file
|
||||
|
||||
console.log('body: ',req.body)
|
||||
// console.log('body.data: ',.data)
|
||||
// console.log('body.pos: ',body.pos)
|
||||
console.log('file: ',file)
|
||||
// console.log('pos: ',pos)
|
||||
// console.log('isEnd: ',isEnd)
|
||||
// console.log('fileName: ',fileName)
|
||||
|
||||
const filePieceObj={
|
||||
pos,
|
||||
isEnd,
|
||||
file,
|
||||
ogName: fileName,
|
||||
name: file.filename
|
||||
}
|
||||
|
||||
|
||||
|
||||
// if array is empty or last of piece of last file 'isEnd' is true
|
||||
// last piece of last file bcz so that next time when file batch comes
|
||||
// then for next pieces of first file 'isStart': true
|
||||
if(fileObjs.length==0 || getLast(getLast(fileObjs)).isEnd==='true' )
|
||||
{
|
||||
isStart=true
|
||||
|
||||
}
|
||||
else{
|
||||
isStart=false
|
||||
}
|
||||
|
||||
if(isStart)
|
||||
{
|
||||
fileObjs.push([filePieceObj])
|
||||
}
|
||||
else{
|
||||
getLast(fileObjs).push(filePieceObj)
|
||||
}
|
||||
|
||||
if(filePieceObj.isEnd==='true')
|
||||
{
|
||||
console.log('isEnd true ')
|
||||
mergeFile()
|
||||
|
||||
// when all files are recieved here
|
||||
if(fileIndex===total-1)
|
||||
{
|
||||
console.log('final end reached')
|
||||
message+=" All files uploaded."
|
||||
total=0
|
||||
|
||||
res.json({status: 'ok',message, isCompleted: true})
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
console.log('fileObjs: ',fileObjs)
|
||||
res.json({ status: 'ok',message: 'uploaded successfully'})
|
||||
|
||||
}
|
||||
catch(err){
|
||||
console.log('err: ',err)
|
||||
res.json({status: 'error'})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
})
|
||||
|
||||
const server=app.listen(PORT,()=>{
|
||||
console.log('app is running in PORT ',PORT)
|
||||
})
|
||||
```
|
||||
|
||||
Generalized version
|
||||
Front end
|
||||
```js
|
||||
// submitIndividualGeneral(file,HOST/cors-submit/chunks?url=<encoded_url> ,resType,bodyType,method,bodyToBeSent,fileFieldName,chunksize)
|
||||
// after fetch when link is ready message is filelink is expected and status and message field are optional
|
||||
// bodyType is either 'form' or 'file'
|
||||
// method is either 'post' or 'put'
|
||||
const submitIndividualGeneral = async (
|
||||
file,
|
||||
url,
|
||||
resType = "json",
|
||||
bodyType = "form",
|
||||
method = "post",
|
||||
bodyToBeSent = {},
|
||||
fileFieldName = "",
|
||||
chunksize = sliceSize
|
||||
) => {
|
||||
const fileSize = file.size;
|
||||
const fileName = file.name;
|
||||
|
||||
try {
|
||||
console.log("file: ", file);
|
||||
let start = 0;
|
||||
let end = chunksize;
|
||||
|
||||
const filePieces = [];
|
||||
let i = 0;
|
||||
while (end <= fileSize) {
|
||||
const chunk = file.slice(start, end);
|
||||
if (end == fileSize) {
|
||||
filePieces.push({ pos: i, chunk, isEnd: true, fileName });
|
||||
} else {
|
||||
filePieces.push({ pos: i, chunk, isEnd: false });
|
||||
}
|
||||
|
||||
start = end;
|
||||
end += chunksize;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (start < fileSize) {
|
||||
const chunk = file.slice(start, fileSize);
|
||||
filePieces.push({ pos: i, chunk, isEnd: true, fileName });
|
||||
i++;
|
||||
}
|
||||
|
||||
// let fileLinks = [];
|
||||
for (let filePiece of filePieces) {
|
||||
const form = new FormData();
|
||||
|
||||
// form.append('data',{pos: filePiece.pos,isEnd: filePiece.isEnd} )
|
||||
|
||||
let res;
|
||||
|
||||
form.append("pos", filePiece.pos);
|
||||
form.append("isEnd", filePiece.isEnd);
|
||||
form.append("file", filePiece.chunk);
|
||||
|
||||
form.append("fileName", filePiece.fileName);
|
||||
|
||||
form.append("bodyToBeSent", JSON.stringify(bodyToBeSent));
|
||||
|
||||
// body to be sent to proxy will be form but from proxy to target will be file if bodytype is file
|
||||
form.append("bodyType", bodyType);
|
||||
|
||||
if (bodyType === "form") {
|
||||
form.append("fileFieldName", fileFieldName);
|
||||
} else {
|
||||
form.append("fileFieldName", "fname");
|
||||
}
|
||||
|
||||
// form.append("total", total);
|
||||
// form.append("fileIndex", index);
|
||||
|
||||
res = await fetch(url, {
|
||||
method,
|
||||
// headers: {
|
||||
// 'Content-Type': 'multipart/form-data'
|
||||
// },
|
||||
body: form,
|
||||
});
|
||||
|
||||
let data;
|
||||
if (resType === "json") {
|
||||
data = await res.json();
|
||||
} else if (resType === "text") {
|
||||
data = await res.text();
|
||||
}
|
||||
|
||||
console.log("res: ", data);
|
||||
if (filePiece.isEnd === true) {
|
||||
// const fileLink = data;
|
||||
return { status: "ok", data };
|
||||
}
|
||||
|
||||
await promiseSetTimeOut(2000);
|
||||
}
|
||||
|
||||
console.log("file: ", file);
|
||||
console.log("filePieces: ", filePieces);
|
||||
|
||||
return { status: "error" };
|
||||
} catch (err) {
|
||||
console.log("err: ", err);
|
||||
// return { status: "error", message: err };
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const encodedURL = encodeURIComponent(apiUrl);
|
||||
// const proxyURL='http://localhost:8080/cors-submit'
|
||||
// const proxyURL = `${CORS_PROXY}/cors-submit`;
|
||||
const proxyURL = `${CORS_PROXY}/cors-submit/chunks`;
|
||||
|
||||
const fetchurl = `${proxyURL}?url=${encodedURL}`;
|
||||
|
||||
const resData = await submitIndividualGeneral(
|
||||
file,
|
||||
fetchurl,
|
||||
"text",
|
||||
"file",
|
||||
"put"
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
### splitting in nodejs instead of browser
|
||||
|
||||
using buffers
|
||||
```js
|
||||
const fs = require('fs');
|
||||
|
||||
const fileBuffer = fs.readFileSync('small-file.zip'); // Entire file loaded into RAM
|
||||
const CHUNK_SIZE = 50 * 1024 * 1024;
|
||||
|
||||
for (let i = 0; i < fileBuffer.length; i += CHUNK_SIZE) {
|
||||
const chunk = fileBuffer.slice(i, i + CHUNK_SIZE);
|
||||
fs.writeFileSync(`part-${i / CHUNK_SIZE}.part`, chunk);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
using streams for efficiency
|
||||
```js
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Configuration: 50MB in bytes
|
||||
const CHUNK_SIZE = 50 * 1024 * 1024;
|
||||
const sourceFile = 'your-large-file.zip';
|
||||
|
||||
function splitFile(filePath) {
|
||||
const stats = fs.statSync(filePath);
|
||||
const totalParts = Math.ceil(stats.size / CHUNK_SIZE);
|
||||
const fileName = path.basename(filePath);
|
||||
|
||||
for (let i = 0; i < totalParts; i++) {
|
||||
const start = i * CHUNK_SIZE;
|
||||
// The 'end' is inclusive, so we subtract 1
|
||||
const end = Math.min((i + 1) * CHUNK_SIZE - 1, stats.size - 1);
|
||||
|
||||
const readStream = fs.createReadStream(filePath, { start, end });
|
||||
const partName = `${fileName}.part${(i + 1).toString().padStart(3, '0')}`;
|
||||
const writeStream = fs.createWriteStream(partName);
|
||||
|
||||
readStream.pipe(writeStream);
|
||||
|
||||
readStream.on('end', () => {
|
||||
console.log(`Finished writing ${partName}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
splitFile(sourceFile);
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
file upload as body directly
|
||||
|
||||
We need to pipe the data to writestream for this
|
||||
|
||||
```js
|
||||
const express = require("express");
|
||||
const fs = require("fs");
|
||||
const app = express();
|
||||
const port = 8090;
|
||||
|
||||
app.use(express.json({ limit: "10mb" })); // Adjust the limit as needed
|
||||
app.use(express.static(__dirname + "/public"));
|
||||
|
||||
// Handle PUT request with file in the request body
|
||||
app.put("/upload", (req, res) => {
|
||||
console.log("body: ", req.body);
|
||||
console.log("file: ", req.files);
|
||||
|
||||
const wsStream = fs.createWriteStream("uploads/name.mp3");
|
||||
|
||||
req.pipe(wsStream);
|
||||
|
||||
req.on("end", () => {
|
||||
wsStream.close(() => {
|
||||
res.json({ data: "success" });
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Server is running on port ${port}`);
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
Front end
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<input type="file" name="" value="">
|
||||
<button>Submit</button>
|
||||
|
||||
<script>
|
||||
|
||||
const convertToFormData=(obj)=>{
|
||||
const formData=new FormData()
|
||||
for(let prop in obj){
|
||||
|
||||
if (obj[prop] instanceof File) {
|
||||
formData.append(prop, obj[prop], obj[prop].name);
|
||||
}
|
||||
else {
|
||||
formData.append(prop, obj[prop]);
|
||||
}
|
||||
}
|
||||
|
||||
return formData
|
||||
}
|
||||
const fileEle=document.querySelector("input")
|
||||
const button=document.querySelector("button")
|
||||
button.addEventListener("click",()=>{
|
||||
// const url="http://localhost:8085/post"
|
||||
// const encodedURL=encodeURIComponent(url)
|
||||
// const proxyURL='http://localhost:8080/cors-submit'
|
||||
|
||||
// const fetchurl=`${proxyURL}?url=${encodedURL}`
|
||||
|
||||
const fetchurl='upload'
|
||||
|
||||
const fileInput=fileEle.files[0]
|
||||
|
||||
const obj={
|
||||
username: 'hey',
|
||||
pass: '123',
|
||||
fileInput
|
||||
}
|
||||
|
||||
fetch(fetchurl,{
|
||||
method : 'PUT',
|
||||
mode: 'cors',
|
||||
headers: {
|
||||
//'Content-Type' : "multipart/form-data",
|
||||
},
|
||||
body : fileInput
|
||||
})
|
||||
.then(res=>res.json())
|
||||
.then(data=>{
|
||||
console.log('data: ',data)
|
||||
})
|
||||
.catch(err=>{
|
||||
console.log('err: ',err)
|
||||
})
|
||||
|
||||
} )
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
logging in text file
|
||||
|
||||
in order for console.log to write output in log.txt file
|
||||
|
||||
```js
|
||||
const consoleWrite = (...data) => {
|
||||
const date = new Date();
|
||||
|
||||
// date.toLocaleString()
|
||||
|
||||
fs.appendFileSync(`${__dirname}/log.txt`, `${date.toLocaleString()}\n`);
|
||||
fs.appendFileSync(`${__dirname}/log.txt`, JSON.stringify(data));
|
||||
fs.appendFileSync(`${__dirname}/log.txt`, "\n\n");
|
||||
};
|
||||
|
||||
console.log = consoleWrite;
|
||||
```
|
||||
176
joplin notion extension/Web Development/nodejs/multer.md
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
multer
|
||||
https://blog.logrocket.com/multer-nodejs-express-upload-file/
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
- By default express dont support files in formdata so we need this module
|
||||
```js
|
||||
const multer = require('multer');
|
||||
|
||||
const app = express();
|
||||
|
||||
// Create a multer instance and specify destination for uploaded files
|
||||
const upload = multer({ dest: 'uploads/' });
|
||||
|
||||
// Handle form data and file uploads using multer middleware
|
||||
app.post('/submit-form', upload.single('fileInput'), (req, res) => {
|
||||
// Access form data from req.body
|
||||
const formData = req.body;
|
||||
// Access uploaded file details from req.file
|
||||
const uploadedFile = req.file;
|
||||
|
||||
// Process the form data and uploaded file
|
||||
// ...
|
||||
|
||||
// Send a response
|
||||
res.send('File uploaded and form data received.');
|
||||
});
|
||||
|
||||
// Start the server
|
||||
const PORT = 3000;
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Server is running on port ${PORT}`);
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
req.file is js object like this
|
||||
```js
|
||||
{
|
||||
fieldname: 'file', // Name of the form field specified in HTML
|
||||
originalname: 'photo.jpg', // Name of the file on the user's computer
|
||||
encoding: '7bit', // Encoding type of the file
|
||||
mimetype: 'image/jpeg', // The MIME type of the file
|
||||
destination: 'uploads/', // The folder where the file has been saved
|
||||
filename: '1714632000-photo.jpg', // The name of the file within the destination
|
||||
path: 'uploads/1714632000-photo.jpg', // The full path to the uploaded file
|
||||
size: 354612 // Size of the file in bytes
|
||||
}
|
||||
```
|
||||
- For multiple file uploads
|
||||
```js
|
||||
app.post('/submit-form', upload.array('fileInputs', 3), (req, res) => {
|
||||
// Access form data from req.body
|
||||
const formData = req.body;
|
||||
// Access uploaded files details from req.files
|
||||
const uploadedFiles = req.files;
|
||||
```
|
||||
|
||||
- For dynamic file fieldname
|
||||
```js
|
||||
app.post('/submit-form', upload.any(), (req, res) => {
|
||||
// Access form data from req.body
|
||||
const formData = req.body;
|
||||
// Access uploaded files details from req.files
|
||||
const uploadedFiles = req.files;
|
||||
```
|
||||
|
||||
Here 2nd argument in upload.array() ie 3 is optional. fileInputs is required name which is name of field containing files
|
||||
|
||||
|
||||
- Frontend part
|
||||
```html
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>File Upload</h1>
|
||||
<form id='form'>
|
||||
<div class="input-group">
|
||||
<label for='name'>Your name</label>
|
||||
<input name='name' id='name' placeholder="Enter your name" />
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for='files'>Select files</label>
|
||||
<input id='files' type="file" multiple>
|
||||
</div>
|
||||
<button class="submit-btn" type='submit'>Upload</button>
|
||||
</form>
|
||||
</div>
|
||||
<script src='./script.js'></script>
|
||||
</body>
|
||||
```
|
||||
|
||||
```css
|
||||
/* style.css */
|
||||
body {
|
||||
background-color: rgb(6, 26, 27);
|
||||
}
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.container {
|
||||
max-width: 500px;
|
||||
margin: 60px auto;
|
||||
}
|
||||
.container h1 {
|
||||
text-align: center;
|
||||
color: white;
|
||||
}
|
||||
form {
|
||||
background-color: white;
|
||||
padding: 30px;
|
||||
}
|
||||
form .input-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
form label {
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
form input {
|
||||
padding: 12px 20px;
|
||||
width: 100%;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
border: none;
|
||||
background: rgb(37, 83, 3);
|
||||
font-size: 18px;
|
||||
color: white;
|
||||
border-radius: 3px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
```
|
||||
|
||||
```js
|
||||
// script.js
|
||||
const form = document.getElementById("form");
|
||||
|
||||
form.addEventListener("submit", submitForm);
|
||||
|
||||
function submitForm(e) {
|
||||
e.preventDefault();
|
||||
const name = document.getElementById("name");
|
||||
const files = document.getElementById("files");
|
||||
const formData = new FormData();
|
||||
formData.append("name", name.value);
|
||||
for(let i =0; i < files.files.length; i++) {
|
||||
formData.append("files", files.files[i]);
|
||||
}
|
||||
fetch("http://localhost:5000/upload_files", {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
headers: {
|
||||
"Content-Type": "multipart/form-data"
|
||||
}
|
||||
})
|
||||
.then((res) => console.log(res))
|
||||
.catch((err) => ("Error occured", err));
|
||||
}
|
||||
```
|
||||
|
||||
or using just javascript instead of form element in html
|
||||
```js
|
||||
const files = document.getElementById("files").files;
|
||||
const formData = new FormData();
|
||||
files.forEach((file) => {
|
||||
formData.append("fileInputs", file); // Append files to the FormData object
|
||||
});
|
||||
// this header
|
||||
// "content-type" : "multipart/form-data"
|
||||
// can cause error so if that occurs dont include this header
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
mysql connect
|
||||
|
||||
Install it first using `npm i mysql2` as mysql v1 may have some issues
|
||||
```js
|
||||
|
||||
const mysql = require("mysql");
|
||||
|
||||
const con = mysql.createConnection({
|
||||
host: "localhost",
|
||||
user: "root",
|
||||
password: "password",
|
||||
database: "hospitals",
|
||||
multipleStatements: true,
|
||||
});
|
||||
|
||||
app.post("/register", (req, res) => {
|
||||
const { name, address, email, phone_no, password } = req.body;
|
||||
const { patient_photo } = req.files;
|
||||
const patientPhotoPathname = patient_photo.path;
|
||||
|
||||
|
||||
// Store the registration details
|
||||
con.query(
|
||||
`use hospitals;
|
||||
insert into patients(name,address,email,phone_no,password,patient_photo_path)
|
||||
values ('${name}','${address}','${email}','${phone_no}','${password}','${patientPhotoPathname}')
|
||||
`,
|
||||
(err, result) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
|
||||
res
|
||||
.status(400)
|
||||
.json("Error while registering. Email address must be unique");
|
||||
} else {
|
||||
console.log(result);
|
||||
res.json("Registered");
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
app.get("/fetch", (req, res) => {
|
||||
const { hospital_id } = req.body;
|
||||
|
||||
// console.log("body:", req.body);
|
||||
const sqlquery = `select hospital_id,count(psychiatrists.id) as psychiatrist_count,
|
||||
sum(patients_count) as total_patients_count,hospital.name
|
||||
from psychiatrists,hospital
|
||||
where hospital.id=psychiatrists.hospital_id and hospital_id=${hospital_id};
|
||||
select id,name,patients_count from psychiatrists
|
||||
where hospital_id=${hospital_id};
|
||||
`;
|
||||
|
||||
con.query(sqlquery, (err, result) => {
|
||||
if (err) {
|
||||
res.status(500).json("Some error while fetching");
|
||||
console.log(err);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(result);
|
||||
}
|
||||
```
|
||||
|
||||
- handling disconnection due to idle timeout
|
||||
```js
|
||||
function handleDisconnect() {
|
||||
con = mysql.createConnection(dbConfig); // Recreate the connection, since the old one cannot be reused.
|
||||
con.connect(function onConnect(err) {
|
||||
// The server is either down
|
||||
if (err) {
|
||||
// or restarting (takes a while sometimes).
|
||||
console.log("error when connecting to db:", err);
|
||||
setTimeout(handleDisconnect, 10000); // We introduce a delay before attempting to reconnect,
|
||||
} // to avoid a hot loop, and to allow our node script to
|
||||
}); // process asynchronous requests in the meantime.
|
||||
// If you're also serving http, display a 503 error.
|
||||
con.on("error", function onError(err) {
|
||||
console.log("db error", err);
|
||||
// if (err.code == "PROTOCOL_CONNECTION_LOST") {
|
||||
// // Connection to the MySQL server is usually
|
||||
// handleDisconnect(); // lost due to either server restart, or a
|
||||
// } else {
|
||||
// // connnection idle timeout (the wait_timeout
|
||||
// throw err; // server variable configures this)
|
||||
// }
|
||||
handleDisconnect();
|
||||
});
|
||||
}
|
||||
handleDisconnect();
|
||||
|
||||
con.on("connection", () => {
|
||||
console.log("db connected");
|
||||
});
|
||||
|
||||
```
|
||||
52
joplin notion extension/Web Development/nodejs/ngrok.md
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
ngrok
|
||||
https://reyhann.medium.com/how-to-expose-your-localhost-server-using-ngrok-9928ac2e26b8
|
||||
https://www.npmjs.com/package/ngrok
|
||||
|
||||
- adding token through command
|
||||
`ngrok config add-authtoken <TOKEN>`
|
||||
|
||||
```js
|
||||
const PORT = process.env.PORT || 8080;
|
||||
(async function () {
|
||||
try {
|
||||
await ngrok.authtoken(token);
|
||||
const url = await ngrok.connect(PORT);
|
||||
console.log("url: ", url);
|
||||
} catch (err) {
|
||||
console.log("err: ", err);
|
||||
}
|
||||
})();
|
||||
```
|
||||
|
||||
- for multiple accounts in same machine
|
||||
https://jd-bots.com/2022/03/04/how-to-use-multiple-ngrok-accounts-on-one-computer-in-windows/
|
||||
`ngrok http 80 -config="C:\Users\jagdish\.ngrok2\my-ngrok-2.yml"`
|
||||
format of `ngrok.yml`
|
||||
```yml
|
||||
version: "2"
|
||||
authtoken: <AUTH_TOKEN>
|
||||
```
|
||||
|
||||
- in shell
|
||||
ngrok http 80 (here 80 is port number)
|
||||
- in termux
|
||||
to fix "failed get HOME directory"
|
||||
first you need to type "whoami" without quote in your termux.
|
||||
that will showed the user
|
||||
~ $ whoami
|
||||
u0_a185l
|
||||
|
||||
copy the output (u0_a185l) for me.
|
||||
than add the user to path by typing "export USER=u0_a185l"
|
||||
~ $ export USER=u0_a185
|
||||
enter.
|
||||
and re-run ngrok
|
||||
~ $ ./ngrok
|
||||
or
|
||||
https://github.com/Yisus7u7/termux-ngrok/
|
||||
- using wifi instead of mobile data in termux
|
||||
https://www.youtube.com/watch?v=EGaZ9SajayY
|
||||
simply use proot-distro and use ngrok from there, ngrok if installed in termux will work just have to configure auth-token separately
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
npm modules
|
||||
|
||||
- ytpl
|
||||
to get information about youtube playlist
|
||||
https://github.com/TimeForANinja/node-ytpl/
|
||||
Exception : https://www.youtube.com/playlist?list=PLi01XoE8jYojRqM4qGBF1U90Ee1Ecb5tt
|
||||
not working for this playlist.just returning title, channel id and count of videos, not the video URLs
|
||||
- recommended versions
|
||||
```json
|
||||
"node-fetch": "^2.6.7"
|
||||
```
|
||||
- https://github.com/iqbal-rashed/ytdlp-nodejs : based on yt-dlp (not working)
|
||||
https://www.npmjs.com/package/yt-dlp-wrap (working)
|
||||
- okay so after further investigating, switching from version
|
||||
```"ytdl-core": "github:khlevon/node-ytdl-core#v4.11.4-patch.2",```
|
||||
to something like
|
||||
```"ytdl-core": "npm:@distube/ytdl-core@^4.13.3",```
|
||||
makes the "parse decipher" error go away and the files download properly
|
||||
165
joplin notion extension/Web Development/nodejs/playwright.md
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
playwright
|
||||
https://playwright.dev/docs/intro
|
||||
|
||||
- `npm i playwright` and `npx playwright install firefox` to download firefox
|
||||
- Normal branded firefox wont work with playwright. playwright will download its own patch of firefox
|
||||
|
||||
Simple example
|
||||
```js
|
||||
const { firefox } = require("playwright");
|
||||
|
||||
(async () => {
|
||||
const browser = await firefox.launch({
|
||||
// executablePath: "/usr/lib/firefox/firefox",
|
||||
headless: false,
|
||||
});
|
||||
const page = await browser.newPage();
|
||||
await page.goto("https://playwright.dev/");
|
||||
|
||||
// .DocSearch is a CSS selector for search button
|
||||
await page.locator(".DocSearch").click();
|
||||
// await browser.close();
|
||||
})();
|
||||
|
||||
```
|
||||
- In order to preserve profile use `launchPersistentContext` method instead of `launch`.
|
||||
eg
|
||||
```js
|
||||
const { firefox } = require("playwright");
|
||||
|
||||
(async () => {
|
||||
const browser = await firefox.launchPersistentContext(
|
||||
"/home/hpes/.mozilla/firefox/r7e7y6qd.playwright",
|
||||
{
|
||||
// executablePath: "/usr/lib/firefox/firefox",
|
||||
headless: false,
|
||||
timeout: 0,
|
||||
// args: ["--profile-directory=playwright"],
|
||||
}
|
||||
);
|
||||
const page = await browser.newPage();
|
||||
await page.goto("https://rumble.com");
|
||||
// await page.locator(".DocSearch").click();
|
||||
// await browser.close();
|
||||
})();
|
||||
|
||||
```
|
||||
|
||||
- for uploading videos in rumble
|
||||
```js
|
||||
const promiseSetTimeout = (time) => {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, time);
|
||||
});
|
||||
};
|
||||
|
||||
const { firefox } = require("playwright");
|
||||
const path = require("path");
|
||||
|
||||
const videoTitle = "The Witcher 3 evil soft first touches p3 toad price fight";
|
||||
const tagsValue = "#gaming #witcher3";
|
||||
const channelValue = "6448233";
|
||||
|
||||
const video_dirname =
|
||||
"/mnt/hdd/windows/witcher 3 reocrded videos/1080p/original/missions/hos/evil soft first touches/";
|
||||
|
||||
const video_filename =
|
||||
"The Witcher 3 evil soft first touches p3 toad price fight.mp4";
|
||||
|
||||
const thumbnail_dirname =
|
||||
"/mnt/hdd/windows/witcher 3 reocrded videos/1080p/original/missions/hos/evil soft first touches/assets";
|
||||
const thumbnail_filename =
|
||||
"evil soft first touches p3 fighting toad prince.png";
|
||||
(async () => {
|
||||
const browser = await firefox.launchPersistentContext(
|
||||
"/home/hpes/.mozilla/firefox/r7e7y6qd.playwright",
|
||||
{
|
||||
// executablePath: "/usr/lib/firefox/firefox",
|
||||
headless: false,
|
||||
timeout: 0,
|
||||
// args: ["--profile-directory=playwright"],
|
||||
}
|
||||
);
|
||||
|
||||
// const page1 = await browser.newPage();
|
||||
// const page2 = await browser.newPage();
|
||||
|
||||
// await page1.goto("https://rumble.com/upload.php");
|
||||
// await page2.goto("https://rumble.com/upload.php");
|
||||
|
||||
// await page1.waitForSelector(".title");
|
||||
|
||||
// const videoCompleteh3Handle = await page1.locator(".title");
|
||||
|
||||
// // completion of upload successfully
|
||||
// videoCompleteh3Handle.innerText() === "Video Upload Complete!";
|
||||
|
||||
const page = await browser.newPage();
|
||||
|
||||
await page.goto("https://rumble.com/upload.php");
|
||||
|
||||
// filling video title
|
||||
await page.locator("#title").fill(videoTitle);
|
||||
|
||||
// filling primary category
|
||||
await page
|
||||
.locator(
|
||||
".video-details > div:nth-child(7) > div:nth-child(1) > div:nth-child(1) > input:nth-child(2)"
|
||||
)
|
||||
.fill("Gaming");
|
||||
|
||||
// filling tags
|
||||
await page.locator("#tags").fill(tagsValue);
|
||||
|
||||
const selectHandle = await page.locator("#channelId");
|
||||
|
||||
selectHandle.selectOption(channelValue);
|
||||
|
||||
const uploadVideoHandle = await page.locator("#Filedata");
|
||||
|
||||
uploadVideoHandle.setInputFiles(path.join(video_dirname, video_filename));
|
||||
|
||||
await promiseSetTimeout(3000);
|
||||
|
||||
// uploading custom thumbnail
|
||||
const uploadThumbnailHandle = await page.locator("#customThumb");
|
||||
uploadThumbnailHandle.setInputFiles(
|
||||
path.join(thumbnail_dirname, thumbnail_filename)
|
||||
);
|
||||
|
||||
await promiseSetTimeout(2000);
|
||||
|
||||
const uploadButtonHandle = await page.locator("#submitForm");
|
||||
|
||||
// go to next step for final submission
|
||||
uploadButtonHandle.click();
|
||||
|
||||
await promiseSetTimeout(4000);
|
||||
|
||||
// checking checkboxes before final submission
|
||||
// await page.locator("#crights").check();
|
||||
// await page.locator("#cterms").check();
|
||||
|
||||
// await page.locator("#crights").click();
|
||||
// await page.locator("#cterms").click();
|
||||
|
||||
// crights
|
||||
await page
|
||||
.locator("div.form-checkbox:nth-child(2) > label:nth-child(2)")
|
||||
.click();
|
||||
|
||||
// cterms
|
||||
await page
|
||||
.locator("div.form-checkbox:nth-child(3) > label:nth-child(2)")
|
||||
.click();
|
||||
|
||||
await promiseSetTimeout(2000);
|
||||
|
||||
// finally submitting it
|
||||
// await page.locator("#submitForm2").click();
|
||||
|
||||
// await page.locator(".DocSearch").click();
|
||||
// await browser.close();
|
||||
})();
|
||||
|
||||
```
|
||||
220
joplin notion extension/Web Development/nodejs/postgresql.md
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
postgresql
|
||||
|
||||
- Install pg module
|
||||
https://node-postgres.com/
|
||||
For multiple queries there r 2 methods
|
||||
|
||||
In Node.js, when using the `pg` library (node-postgres) to work with PostgreSQL databases, executing multiple queries consecutively is a common requirement. There are several ways to achieve this depending on the nature of your queries and how they should be executed (e.g., in parallel, in sequence, within a transaction). Below are some approaches:
|
||||
|
||||
|
||||
|
||||
#### 1. Sequential Execution (with async/await)
|
||||
If your queries are dependent on each other and need to be executed in a sequential manner, you can use `async/await` syntax to execute them one after the other.
|
||||
|
||||
```javascript
|
||||
const { Client } = require('pg');
|
||||
|
||||
const client = new Client({
|
||||
// Your database connection parameters
|
||||
});
|
||||
|
||||
const executeQueriesSequentially = async () => {
|
||||
try {
|
||||
await client.connect();
|
||||
const result1 = await client.query('SELECT * FROM table1;');
|
||||
console.log('Result 1:', result1.rows);
|
||||
const result2 = await client.query('SELECT * FROM table2;');
|
||||
console.log('Result 2:', result2.rows);
|
||||
// Continue for more queries
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
} finally {
|
||||
await client.end();
|
||||
}
|
||||
};
|
||||
|
||||
executeQueriesSequentially();
|
||||
```
|
||||
|
||||
#### 2. Parallel Execution
|
||||
If your queries are independent of each other, you can execute them in parallel using `Promise.all`.
|
||||
|
||||
```javascript
|
||||
const executeQueriesInParallel = async () => {
|
||||
try {
|
||||
await client.connect();
|
||||
const promises = [
|
||||
client.query('SELECT * FROM table1;'),
|
||||
client.query('SELECT * FROM table2;'),
|
||||
// Add more queries as needed
|
||||
];
|
||||
const results = await Promise.all(promises);
|
||||
results.forEach((result, index) => {
|
||||
console.log(`Result ${index + 1}:`, result.rows);
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
} finally {
|
||||
await client.end();
|
||||
}
|
||||
};
|
||||
|
||||
executeQueriesInParallel();
|
||||
```
|
||||
|
||||
### 3. Using Transactions
|
||||
For cases where your queries must be executed as a single atomic operation, you will want to use a transaction. This is particularly important i
|
||||
|
||||
|
||||
|
||||
## Defending from SQL injection
|
||||
Also this way will prevent from situation like when we use `insert into tablename values ('${str}')` and if str is `i won't do` then it will like `insert into tablename values ('i won't do)` so strng will be `i won` as later is single quote closing in.
|
||||
|
||||
This method is called parameterized queries or prepared statements instead of manually constructing query strings which handles sql injection and escaping characters.
|
||||
|
||||
- For PostgreSQL (pg package example):
|
||||
```js
|
||||
const { Pool } = require('pg')
|
||||
const pool = new Pool()
|
||||
|
||||
const text = 'INSERT INTO your_table(name) VALUES($1,$2)'
|
||||
const values = [`there isn't anything to do`, `ok go`]
|
||||
|
||||
pool.query(text, values, (err, res) => {
|
||||
if (err) {
|
||||
console.log(err.stack)
|
||||
} else {
|
||||
console.log(res.rows[0])
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
- For MySQL (mysql package example):
|
||||
```js
|
||||
const mysql = require('mysql');
|
||||
const connection = mysql.createConnection({
|
||||
host: 'example.org',
|
||||
user: 'your_user',
|
||||
password: 'your_pass',
|
||||
database: 'your_db'
|
||||
});
|
||||
|
||||
connection.connect();
|
||||
|
||||
const post = {name: `there isn't anything to do`};
|
||||
const query = connection.query('INSERT INTO your_table SET ?', post, (err, result) => {
|
||||
if (err) throw err;
|
||||
|
||||
console.log(result);
|
||||
});
|
||||
|
||||
connection.end();
|
||||
```
|
||||
|
||||
|
||||
### Reconnecting database
|
||||
Sometimes database gets disconnected. There r various ways like reconnecting ir but few things needed to be noted. When reconnecting sometimes we need to create new object too instead of just reconnecting
|
||||
Eg:
|
||||
```js
|
||||
const pg = require("pg");
|
||||
let pgClient
|
||||
|
||||
const createPGConnection=()=>{
|
||||
pgClient=new pg.Client(conString);
|
||||
|
||||
pgClient.connect()
|
||||
console.log('database connected')
|
||||
|
||||
}
|
||||
|
||||
const conString = process.env.CONNECTION_URI;
|
||||
|
||||
|
||||
client.on("ready", async () => {
|
||||
console.log(`Logged in as ${client.user.tag}!`);
|
||||
|
||||
|
||||
});
|
||||
|
||||
createPGConnection()
|
||||
|
||||
pgClient.on('error',async(err)=>{
|
||||
console.log('err: ',err)
|
||||
await pgClient.end()
|
||||
console.log('connection ended')
|
||||
console.log('trying to reconnect')
|
||||
await promiseSetTimeOut(5000)
|
||||
await createPGConnection()
|
||||
})
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
**Pooling**
|
||||
https://node-postgres.com/features/pooling
|
||||
```js
|
||||
import pg from "pg";
|
||||
|
||||
const { Pool } = pg;
|
||||
|
||||
const poolConfig = {
|
||||
user: process.env.PGUSER,
|
||||
password: process.env.PGPASSWORD,
|
||||
database: process.env.PGDATABASE,
|
||||
host: process.env.PGHOST,
|
||||
port: process.env.PGPORT,
|
||||
max: 20,
|
||||
idleTimeoutMillis: 30000,
|
||||
connectionTimeoutMillis: 5000,
|
||||
};
|
||||
|
||||
export const pool = new Pool(poolConfig);
|
||||
|
||||
pool.on("error", (error) => {
|
||||
console.error("unexpected error on idle client:", error.message);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
export const query = (text, params) => pool.query(text, params);
|
||||
```
|
||||
some testing
|
||||
```js
|
||||
const test = async () => {
|
||||
try {
|
||||
await query("SELECT 1");
|
||||
console.log("database connected bro.");
|
||||
return true;
|
||||
} catch (err) {
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
transactions
|
||||
```js
|
||||
|
||||
|
||||
import { Pool } from 'pg'
|
||||
const pool = new Pool()
|
||||
|
||||
const client = await pool.connect()
|
||||
|
||||
try {
|
||||
await client.query('BEGIN')
|
||||
const queryText = 'INSERT INTO users(name) VALUES($1) RETURNING id'
|
||||
const res = await client.query(queryText, ['brianc'])
|
||||
|
||||
const insertPhotoText = 'INSERT INTO photos(user_id, photo_url) VALUES ($1, $2)'
|
||||
const insertPhotoValues = [res.rows[0].id, 's3.bucket.foo']
|
||||
await client.query(insertPhotoText, insertPhotoValues)
|
||||
await client.query('COMMIT')
|
||||
} catch (e) {
|
||||
await client.query('ROLLBACK')
|
||||
throw e
|
||||
} finally {
|
||||
client.release()
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
json to sqlite db
|
||||
|
||||
```js
|
||||
const jsonToSQL = (
|
||||
json = "",
|
||||
rootPath = ".",
|
||||
dbfilename = "db.db",
|
||||
tablename = "tablename",
|
||||
primaryKeyField,
|
||||
isAppendMode = false
|
||||
) => {
|
||||
const originalSchemaPath = `${rootPath}/originalSchema.json`;
|
||||
const parsedSchemaPath = `${rootPath}/parsedSchema.json`;
|
||||
|
||||
const jsonData = JSON.parse(json);
|
||||
const db = new Database(`${rootPath}/${dbfilename}`);
|
||||
// console.log(typeof [1, 2]);
|
||||
// console.log(jsonData);
|
||||
|
||||
// db.exec(`drop table if exists ${tablename}`);
|
||||
// db.exec(`delete from ${tablename}`);
|
||||
|
||||
const isArray = Array.isArray(jsonData);
|
||||
|
||||
let finalData = jsonData;
|
||||
|
||||
// if not an array then converting to array
|
||||
if (!isArray) {
|
||||
finalData = Object.values(finalData);
|
||||
}
|
||||
|
||||
let originalSchemaWrapper = {};
|
||||
|
||||
let parsedSchemaWrapper = {};
|
||||
|
||||
const originalSchema = {};
|
||||
const parsedSchema = {};
|
||||
|
||||
// retrieving schema stored earlier
|
||||
if (fs.existsSync(originalSchemaPath)) {
|
||||
const value = JSON.parse(fs.readFileSync(originalSchemaPath));
|
||||
originalSchemaWrapper = value;
|
||||
Object.assign(originalSchema, value[tablename] ?? {});
|
||||
}
|
||||
|
||||
if (fs.existsSync(parsedSchemaPath)) {
|
||||
const value = JSON.parse(fs.readFileSync(parsedSchemaPath));
|
||||
parsedSchemaWrapper = value;
|
||||
Object.assign(parsedSchema, value[tablename] ?? {});
|
||||
}
|
||||
|
||||
const createTable = () => {
|
||||
if (finalData.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const firstData = finalData[0];
|
||||
if (typeof firstData != "object" || firstData === null) {
|
||||
throw new Error("invalid format");
|
||||
}
|
||||
|
||||
// key value pair of fieldname and type, both are strings
|
||||
|
||||
for (let key in firstData) {
|
||||
originalSchema[key] = typeof firstData[key];
|
||||
}
|
||||
|
||||
const sqlColumnsInfoArray = [];
|
||||
for (let colname in originalSchema) {
|
||||
// to check if current column name is of primary key or not
|
||||
const isPrimaryKey =
|
||||
primaryKeyField != undefined &&
|
||||
primaryKeyField != null &&
|
||||
primaryKeyField == colname;
|
||||
|
||||
// console.log(colname, " isPrimaryKey: ", isPrimaryKey);
|
||||
if (originalSchema[colname] == "number") {
|
||||
parsedSchema[colname] = "numeric";
|
||||
} else if (originalSchema[colname] == "boolean") {
|
||||
parsedSchema[colname] = "integer";
|
||||
|
||||
// everything else is text as text can even store numbers too after being parsed to string so useful for nulls
|
||||
} else {
|
||||
parsedSchema[colname] = "text";
|
||||
}
|
||||
|
||||
sqlColumnsInfoArray.push(
|
||||
`${colname} ${parsedSchema[colname]} ${
|
||||
isPrimaryKey ? "primary key" : ""
|
||||
}`
|
||||
);
|
||||
}
|
||||
|
||||
const sqlCreateQuery = `create table if not exists ${tablename} (
|
||||
${sqlColumnsInfoArray.join(",")}
|
||||
);`;
|
||||
|
||||
// console.log(sqlCreateQuery);
|
||||
const result = db.exec(sqlCreateQuery);
|
||||
};
|
||||
|
||||
const insertTable = (record) => {
|
||||
if (typeof record != "object" || record == null) {
|
||||
throw new Error("invalid format");
|
||||
}
|
||||
|
||||
for (let key in record) {
|
||||
if (!Object.hasOwn(originalSchema, key)) {
|
||||
let newSqlColumnInfo = "";
|
||||
originalSchema[key] = typeof record[key];
|
||||
|
||||
if (originalSchema[key] == "number") {
|
||||
parsedSchema[key] = "number";
|
||||
} else if (originalSchema[key] == "boolean") {
|
||||
parsedSchema[key] = "integer";
|
||||
// newSqlColumnsInfoArray.push(`${key} integer`);
|
||||
|
||||
// everything else is text as text can even store numbers too after being parsed to string so useful for nulls
|
||||
} else {
|
||||
parsedSchema[key] = "text";
|
||||
// newSqlColumnsInfoArray.push(`${key} text `);
|
||||
}
|
||||
|
||||
newSqlColumnInfo = `${key} ${parsedSchema[key]} `;
|
||||
|
||||
db.exec(`alter table ${tablename} add column ${newSqlColumnInfo}`);
|
||||
}
|
||||
}
|
||||
|
||||
const columns_string = Object.keys(record).join(",");
|
||||
|
||||
const valuesArray = [];
|
||||
|
||||
for (let column in record) {
|
||||
// if text
|
||||
if (parsedSchema[column] === "text") {
|
||||
// check if value is null or not
|
||||
if (record[column] === null) {
|
||||
valuesArray.push(null);
|
||||
}
|
||||
// if value is string then simply pushing it
|
||||
else if (typeof record[column] === "string") {
|
||||
valuesArray.push(record[column]);
|
||||
}
|
||||
// if its number or array or object it will be stringified accordingly
|
||||
else {
|
||||
valuesArray.push(JSON.stringify(record[column]));
|
||||
}
|
||||
}
|
||||
// if its boolean
|
||||
else if (parsedSchema[column] === "integer") {
|
||||
valuesArray.push(record[column] ? 1 : 0);
|
||||
|
||||
// if its number
|
||||
} else {
|
||||
valuesArray.push(record[column]);
|
||||
}
|
||||
}
|
||||
|
||||
// const valuesPlaceholderArray =
|
||||
const values_placeholders_string = new Array(valuesArray.length)
|
||||
.fill("?")
|
||||
.join(",");
|
||||
|
||||
const insertStatement = db.prepare(
|
||||
`insert into ${tablename} (${columns_string}) values (${values_placeholders_string}) `
|
||||
);
|
||||
|
||||
const info = insertStatement.run(...valuesArray);
|
||||
|
||||
// console.log("info: ", info);
|
||||
};
|
||||
|
||||
if (Object.keys(originalSchema).length === 0) {
|
||||
createTable();
|
||||
} else {
|
||||
if (!isAppendMode) {
|
||||
db.exec(`delete from ${tablename}`);
|
||||
}
|
||||
}
|
||||
|
||||
for (let record of finalData) {
|
||||
insertTable(record);
|
||||
}
|
||||
|
||||
// console.log("result: ", result);
|
||||
|
||||
// const insertStatement = db.exec(
|
||||
// "create table if not exists channels (info text)"
|
||||
// );
|
||||
|
||||
// console.log("insertStatement: ", insertStatement);
|
||||
|
||||
originalSchemaWrapper[tablename] = originalSchema;
|
||||
parsedSchemaWrapper[tablename] = parsedSchema;
|
||||
|
||||
fs.writeFileSync(originalSchemaPath, JSON.stringify(originalSchemaWrapper));
|
||||
fs.writeFileSync(parsedSchemaPath, JSON.stringify(parsedSchemaWrapper));
|
||||
|
||||
// console.log("done");
|
||||
|
||||
console.log(`converted json to table ${tablename} in db ${dbfilename}`);
|
||||
};
|
||||
```
|
||||
|
|
@ -0,0 +1,267 @@
|
|||
padloc To Keepaas
|
||||
|
||||
`app.js`
|
||||
```js
|
||||
const fs =require('fs')
|
||||
|
||||
const {getRecords} = require('./helpers')
|
||||
|
||||
const filename= 'My_Vault_2024-05-13.csv'
|
||||
// const filename= 'test.csv'
|
||||
|
||||
|
||||
|
||||
|
||||
const outputDataFile = "output.xml"
|
||||
|
||||
let outputData=""
|
||||
|
||||
outputData+=`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<KeePassFile>
|
||||
<Meta/>
|
||||
<Root>
|
||||
<Group>
|
||||
<Name>Root</Name>
|
||||
<Notes/>
|
||||
<IconID>48</IconID>
|
||||
<Times/>
|
||||
<IsExpanded>True</IsExpanded>
|
||||
<DefaultAutoTypeSequence/>
|
||||
<EnableAutoType>null</EnableAutoType>
|
||||
<EnableSearching>null</EnableSearching>
|
||||
<Group>
|
||||
<Name>padloc</Name>
|
||||
<Notes>containing prev padloc database</Notes>
|
||||
<IconID>48</IconID>
|
||||
<Times/>
|
||||
<IsExpanded>True</IsExpanded>
|
||||
<DefaultAutoTypeSequence/>
|
||||
<EnableAutoType>null</EnableAutoType>
|
||||
<EnableSearching>null</EnableSearching>
|
||||
`
|
||||
|
||||
|
||||
const records = getRecords(filename)
|
||||
|
||||
// function to map names of keys to match that of keepaas ones
|
||||
const mapObjects=(obj)=>{
|
||||
|
||||
const newObj={}
|
||||
for(let key of Object.keys(obj)){
|
||||
|
||||
if(obj[key].length===0){
|
||||
continue;
|
||||
}
|
||||
|
||||
// console.log('key to be mapped: ',key, ' value: ', obj[key])
|
||||
|
||||
switch(key){
|
||||
case 'name': newObj['Title']=obj['name']; break;
|
||||
case 'tags' : newObj['Tags']= obj['tags']; break;
|
||||
case 'Username' : newObj['UserName'] = obj['Username']; break;
|
||||
case 'Email Address' : newObj['Email'] = obj[key]; break;
|
||||
case 'Plain Text' : newObj['Notes'] = obj[key]; break;
|
||||
case 'Name' : newObj['UserName'] = obj[key]; break;
|
||||
default : newObj[key] = obj[key]
|
||||
}
|
||||
}
|
||||
|
||||
// console.log('newObj: ',newObj)
|
||||
|
||||
return newObj;
|
||||
}
|
||||
|
||||
// function to add escape sequqnce for reserved characters in xml
|
||||
const mapValueForXML=(str)=>{
|
||||
let newStr= str.replace(/"/g,'')
|
||||
newStr = newStr.replace(/&/g,'&')
|
||||
newStr = newStr.replace(/</g,'<')
|
||||
newStr = newStr.replace(/>/g,'>')
|
||||
newStr = newStr.replace(/"/g,'"')
|
||||
newStr = newStr.replace(/'/g,''')
|
||||
|
||||
return newStr
|
||||
|
||||
}
|
||||
|
||||
for(let record of records){
|
||||
const tags= record.tags.replace(/"/g,'')
|
||||
|
||||
let tagsXML=''
|
||||
|
||||
if(tags.length===0){
|
||||
tagsXML='<Tags/>'
|
||||
}
|
||||
else{
|
||||
tagsXML=`<Tags>${tags}</Tags>`
|
||||
}
|
||||
|
||||
outputData+=` <Entry>
|
||||
<IconID>0</IconID>
|
||||
<ForegroundColor/>
|
||||
<BackgroundColor/>
|
||||
<OverrideURL/>
|
||||
${tagsXML}
|
||||
<Times/>
|
||||
`
|
||||
|
||||
const mappedRecord = mapObjects(record)
|
||||
// console.log('')
|
||||
for(let key in mappedRecord){
|
||||
|
||||
// console.log('')
|
||||
|
||||
if(key==='Password'){
|
||||
outputData+=` <String>
|
||||
<Key>${key}</Key>
|
||||
<Value ProtectInMemory="True">${ mapValueForXML(mappedRecord[key]) }</Value>
|
||||
</String>
|
||||
`
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
outputData+=` <String>
|
||||
<Key>${key}</Key>
|
||||
<Value>${ mapValueForXML(mappedRecord[key]) }</Value>
|
||||
</String>
|
||||
`
|
||||
}
|
||||
|
||||
outputData+=` <AutoType>
|
||||
<Enabled>True</Enabled>
|
||||
<DataTransferObfuscation>0</DataTransferObfuscation>
|
||||
<DefaultSequence/>
|
||||
</AutoType>
|
||||
<History/>
|
||||
</Entry>
|
||||
`
|
||||
|
||||
}
|
||||
|
||||
outputData+=` </Group>
|
||||
</Group>
|
||||
</Root>
|
||||
</KeePassFile>`
|
||||
|
||||
fs.writeFileSync(outputDataFile,outputData)
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
`helpers.js`
|
||||
```js
|
||||
const fs =require('fs')
|
||||
|
||||
const getRecords=(filename)=>{
|
||||
const data =fs.readFileSync(filename,{encoding : 'utf8'})
|
||||
|
||||
// normal, quotes
|
||||
let state="normal"
|
||||
|
||||
|
||||
|
||||
const lines= data.split('\n')
|
||||
|
||||
// console.log('lines: ',lines)
|
||||
|
||||
// extracting headings and also removing last character ie \r from the line
|
||||
let headings= lines[0].slice(0,lines[0].length-1).split(',')
|
||||
|
||||
console.log('headings: ',headings)
|
||||
|
||||
let valuei=0
|
||||
let str=``
|
||||
|
||||
const parseLine=(line,obj)=>{
|
||||
|
||||
|
||||
// parsing character by character
|
||||
for(let i=0;i<line.length;i++){
|
||||
// comma found in normal state
|
||||
|
||||
if(state==="normal"&& line[i]===','){
|
||||
|
||||
obj[headings[valuei]]=str
|
||||
// resetting buffer for next value
|
||||
str=``
|
||||
// moving to next field index
|
||||
valuei++
|
||||
}
|
||||
|
||||
else if(state==="normal" && line[i]==='"'){
|
||||
state="quotes"
|
||||
str+=line[i]
|
||||
}
|
||||
|
||||
else if(state==="quotes" && line[i]==='"' ){
|
||||
state="normal"
|
||||
str+=line[i]
|
||||
}
|
||||
else{
|
||||
str+=line[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
const records=[]
|
||||
|
||||
let obj={}
|
||||
|
||||
for(let i=1;i < lines.length;i++){
|
||||
|
||||
// const line=lines[i].slice(0,lines[i].length-1)
|
||||
|
||||
// removing `\r` from every record
|
||||
const line=lines[i].replace('\r','')
|
||||
|
||||
parseLine(line,obj)
|
||||
|
||||
// if at end of line, state is normal then it means current record
|
||||
// ends so store last field in object and reset values, pushing record in array
|
||||
if(state==='normal'){
|
||||
obj[headings[valuei]]=str
|
||||
|
||||
records.push(obj)
|
||||
// resetting buffer for next value
|
||||
str=``
|
||||
// moving to next field index
|
||||
valuei=0
|
||||
|
||||
obj={}
|
||||
}
|
||||
// if it in quotes then add newline character to current field
|
||||
else{
|
||||
str+='\n'
|
||||
}
|
||||
|
||||
// const commaSeparateArray= lines[i].split(',')
|
||||
// obj['name']= commaSeparateArray[0]
|
||||
// obj['tags']= commaSeparateArray[1]
|
||||
// obj['Username']=commaSeparateArray[2]
|
||||
// obj['Password']=commaSeparateArray[3]
|
||||
// obj['URL']=commaSeparateArray[4]
|
||||
// obj['Email Address']=commaSeparateArray[]
|
||||
|
||||
// const nameRegex= /^(.*),.*/
|
||||
// const tagsRegex = /^.*,("?.*"?),.*/
|
||||
|
||||
|
||||
}
|
||||
|
||||
console.log('records: ',records)
|
||||
|
||||
return records
|
||||
|
||||
|
||||
}
|
||||
|
||||
module.exports= {getRecords}
|
||||
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
reading large json objects
|
||||
https://sentrytwo.com/14af84439a
|
||||
|
||||
Reading JSON objects
|
||||
```js
|
||||
const fs = require('fs');
|
||||
const JSONStream = require('JSONStream');
|
||||
const es = require('event-stream');
|
||||
|
||||
const inputFile = './largeInput.json';
|
||||
|
||||
const readStream = fs.createReadStream(inputFile)
|
||||
.pipe(JSONStream.parse('reponse.stats.*'))
|
||||
.pipe(es.mapSync(data => {
|
||||
// Process each stat record here
|
||||
console.log(data);
|
||||
|
||||
// For example, you can modify each object:
|
||||
// data.newField = `new value for ${data.id}`;
|
||||
// Then you might want to save it elsewhere or just handle it.
|
||||
}));
|
||||
```
|
||||
|
||||
|
||||
Writing JSON objects
|
||||
```js
|
||||
const fs = require('fs');
|
||||
const JSONStream = require('JSONStream');
|
||||
|
||||
const outputFile = './largeOutput.json';
|
||||
|
||||
const writeStream = fs.createWriteStream(outputFile);
|
||||
const stringifyStream = JSONStream.stringify();
|
||||
|
||||
// Pipe the JSONStream output to your file
|
||||
stringifyStream.pipe(writeStream);
|
||||
|
||||
// Assuming you have a way to generate or fetch your objects
|
||||
for (let i = 0; i < 10000; i++) {
|
||||
const item = { id: i, name: `Item ${i}` };
|
||||
stringifyStream.write(item);
|
||||
}
|
||||
|
||||
// Don't forget to end the stream
|
||||
stringifyStream.end();
|
||||
|
||||
// Optionally, handle the finish event
|
||||
writeStream.on('finish', () => {
|
||||
console.log('Finished writing to file');
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
|
||||
Another one
|
||||
https://www.npmjs.com/package/big-json
|
||||
but at end it is merging
|
||||
|
||||
|
||||
Maybe this one will help which is used to run commands on json file
|
||||
https://www.npmjs.com/package/node-jq
|
||||
|
||||
|
||||
**someone else posted**
|
||||
JSONStream should work correctly for your use case, but if you can' t make it to work, you could use libraries like stream-json, oboe.js or even json-parser. Here is how you could use stream-json:
|
||||
```js
|
||||
const { parser } = require('stream-json');
|
||||
const { streamArray } = require('stream-json/streamers/StreamArray');
|
||||
const fs = require('fs');
|
||||
|
||||
const jsonStream = fs.createReadStream('large-file.json').pipe(parser());
|
||||
|
||||
jsonStream.pipe(streamArray()).on('data', ({key, value}) => {
|
||||
console.log(value); // Processes each item individually as a JavaScript object
|
||||
});
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
using proxy with fetch
|
||||
https://www.zenrows.com/blog/node-fetch-proxy#how-to-use-proxy-with-node-fetch
|
||||
for username and password
|
||||
https://github.com/TooTallNate/proxy-agents/issues/12
|
||||
|
||||
|
||||
```js
|
||||
const fetch = require('node-fetch');
|
||||
|
||||
const proxyUrl = 'http://proxyserver:port';
|
||||
const proxyOptions = {
|
||||
proxy: proxyUrl,
|
||||
headers: {
|
||||
'Proxy-Authorization': 'Basic ' + Buffer.from('username:password').toString('base64')
|
||||
}
|
||||
};
|
||||
|
||||
fetch('http://url-to-fetch', proxyOptions)
|
||||
.then(response => response.text())
|
||||
.then(data => {
|
||||
console.log(data);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
Same with curl
|
||||
`curl -x http://proxyserver:port --proxy-user username:password http://url-to-fetch`
|
||||
for socks5
|
||||
`curl -v --socks5 127.0.0.1:1080 https://icanhazip.com`
|
||||
replace with socks4 for socks4
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
74
joplin notion extension/Web Development/nodejs/socket.io.md
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
socket.io
|
||||
|
||||
- Using with http module
|
||||
```js
|
||||
const PORT = process.env.PORT || 8080;
|
||||
|
||||
const httpServer = require("http").createServer();
|
||||
const socketIO = require("socket.io");
|
||||
|
||||
const io = socketIO(httpServer, {
|
||||
cors: { origin: "*" },
|
||||
});
|
||||
|
||||
// when client connects to the server
|
||||
io.on("connection", (socket) => {
|
||||
console.log(`user connected ${socket.id}`);
|
||||
io.emit("requestKey");
|
||||
|
||||
// when listening to custom event named 'message'
|
||||
socket.on("message", (msgObjs) => {
|
||||
// here using socket.broadcast.emit will send message to all client except the one who originally sent to server
|
||||
|
||||
for (let msgObj of msgObjs) {
|
||||
const id = msgObj.sid;
|
||||
io.to(id).emit("message", msgObj.message, socket.id);
|
||||
}
|
||||
|
||||
// socket.broadcast.emit(
|
||||
// "message",
|
||||
// `${socket.id.substr(0, 2)} said ${message}`
|
||||
// );
|
||||
|
||||
// to send to all including OP, use io.emit
|
||||
// and for particular client use
|
||||
// io.to(socket.id). emit("event", data);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
|
||||
- Using with express
|
||||
```js
|
||||
const express = require('express');
|
||||
const app = express();
|
||||
const socketIO = require('socket.io');
|
||||
|
||||
const PORT = process.env.PORT || 8080;
|
||||
const keys = [];
|
||||
|
||||
// Serve your application on a specific route using Express
|
||||
app.get('/', (req, res) => {
|
||||
res.sendFile(__dirname + '/index.html'); // Replace 'index.html' with your HTML file
|
||||
});
|
||||
|
||||
// Create the HTTP server using Express
|
||||
const server = app.listen(PORT, () => {
|
||||
console.log(`Server is running on port ${PORT}`);
|
||||
});
|
||||
|
||||
// Initialize Socket.io by passing the HTTP server instance
|
||||
const io = socketIO(server, {
|
||||
cors: { origin: "*" },
|
||||
});
|
||||
|
||||
// Socket.io logic
|
||||
io.on("connection", (socket) => {
|
||||
console.log(`User connected: ${socket.id}`);
|
||||
io.emit("requestKey");
|
||||
|
||||
// ... (rest of your Socket.io logic)
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
39
joplin notion extension/Web Development/sql/Redis.md
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
Redis
|
||||
|
||||
- Getting Started
|
||||
https://www.tutorialspoint.com/redis/redis_environment.htm
|
||||
`redis-server` to initiate
|
||||
|
||||
Then in another terminal
|
||||
`redis-cli `
|
||||
|
||||
```
|
||||
redis 127.0.0.1:6379> ping
|
||||
PONG
|
||||
```
|
||||
|
||||
- Connecting to remote server
|
||||
` redis-cli -h host -p port -a password`
|
||||
- Get server information
|
||||
`info` : when connected to redis shell not in just bash
|
||||
|
||||
- retrieving keys
|
||||
Retrieving All Existing Keys
|
||||
As it turns out, every SET command we issued above created a new, unique key within our Redis database. To get a list of all current keys that exist, simply use the KEYS command:
|
||||
> KEYS *
|
||||
1) "title:1"
|
||||
2) "title:2"
|
||||
3) "title"
|
||||
4) "author:2"
|
||||
5) "author"
|
||||
6) "author:1"
|
||||
By following KEYS with an asterisk (*) – which acts as a wildcard search – we’re asking Redis to retrieve all keys in the system. Thus, we not only see our two original title and author keys but also the four enumerated versions that followed as well.
|
||||
|
||||
The syntax following KEYS can be used to search for specific words or phrases within the key, or the exact match as well. Here we want all keys that contain the text 'title':
|
||||
|
||||
> KEYS *title*
|
||||
1) "title:1"
|
||||
2) "title:2"
|
||||
3) "title"
|
||||
- retrieving keys with its values
|
||||
`for i in $(redis-cli KEYS '*'); do echo $i; redis-cli GET $i; done`
|
||||
269
joplin notion extension/Web Development/sql/SQL.md
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
SQL
|
||||
|
||||
https://learnsql.com/blog/sql-basics-cheat-sheet/
|
||||
|
||||
## Joins
|
||||
|
||||
**Example**
|
||||
we have 2 tables named 'first' and 'join'
|
||||
first table
|
||||
|id|name|
|
||||
|--|----|
|
||||
|1|name1|
|
||||
|2|name2|
|
||||
|3|name3|
|
||||
|
||||
Books table
|
||||
|id|user_id|book_name|
|
||||
|--|-------|---------|
|
||||
|1|1|book1|
|
||||
|2|1|book2|
|
||||
|3|1|book3|
|
||||
|4|2|book4|
|
||||
|5|4|book5|
|
||||
|
||||
**Cross product** (first X books)
|
||||
Query
|
||||
```sql
|
||||
select * from first,Books;
|
||||
```
|
||||
|
||||
Output
|
||||
|id|name|id|user_id|book_name|
|
||||
|--|----|--|-------|---------|
|
||||
|1|name1|1|1|book1|
|
||||
|2|name2|1|1|book1|
|
||||
|3|name3|1|1|book1|
|
||||
|1|name1|2|1|book2|
|
||||
|2|name2|2|1|book2|
|
||||
|3|name3|2|1|book2|
|
||||
|1|name1|3|1|book3|
|
||||
|2|name2|3|1|book3|
|
||||
|3|name3|3|1|book3|
|
||||
|1|name1|4|2|book4|
|
||||
|2|name2|4|2|book4|
|
||||
|3|name3|4|2|book4|
|
||||
|1|name1|5|4|book5|
|
||||
|2|name2|5|4|book5|
|
||||
|3|name3|5|4|book5|
|
||||
|
||||
|
||||
|
||||
**Union** ( full outer join ) (first U Books)
|
||||
Query
|
||||
```sql
|
||||
-- for mysql
|
||||
SELECT *
|
||||
FROM first
|
||||
LEFT JOIN Books ON first.id = Books.user_id
|
||||
UNION
|
||||
SELECT *
|
||||
FROM first
|
||||
RIGHT JOIN Books ON first.id = Books.user_id;
|
||||
|
||||
-- for others
|
||||
select * from first FULL JOIN Books
|
||||
ON first.id = Books.user_id ;
|
||||
```
|
||||
Output
|
||||
|id|name|id|user_id|book_name|
|
||||
|--|----|--|-------|---------|
|
||||
|1|name1|1|1|book1|
|
||||
|1|name1|2|1|book2|
|
||||
|1|name1|3|1|book3|
|
||||
|2|name2|4|2|book4|
|
||||
|3|name3||||
|
||||
|||5|4|book5|
|
||||
|
||||
|
||||
|
||||
**Intersection** (inner join) (first ∩ Books)
|
||||
Query
|
||||
```sql
|
||||
select * from first,Books
|
||||
where first.id = Books.user_id;
|
||||
|
||||
-- or
|
||||
|
||||
select * from first JOIN Books
|
||||
ON first.id = Books.user_id ;
|
||||
```
|
||||
Output
|
||||
|id|name|id|user_id|book_name|
|
||||
|--|----|--|-------|---------|
|
||||
|1|name1|1|1|book1|
|
||||
|1|name1|2|1|book2|
|
||||
|1|name1|3|1|book3|
|
||||
|2|name2|4|2|book4|
|
||||
|
||||
|
||||
|
||||
|
||||
**LEFT JOIN** (first U first ∩ Books )
|
||||
Means all of left table and intersection of 2 tables is also included
|
||||
Query
|
||||
```sql
|
||||
SELECT *
|
||||
FROM first
|
||||
LEFT JOIN Books ON first.id = Books.user_id
|
||||
|
||||
-- or
|
||||
|
||||
-- Select all rows from table1 and matching rows from table2
|
||||
SELECT first.*, Books.*
|
||||
FROM first, Books
|
||||
WHERE first.id = Books.user_id
|
||||
UNION ALL
|
||||
-- Select all rows from table1 that have no matching row in table2
|
||||
SELECT first.*, NULL AS id, NULL AS user_id , null as book_name
|
||||
FROM first
|
||||
WHERE first.id NOT IN (SELECT user_id FROM Books);
|
||||
```
|
||||
Output
|
||||
|id|name|id|user_id|book_name|
|
||||
|--|----|--|-------|---------|
|
||||
|1|name1|1|1|book1|
|
||||
|1|name1|2|1|book2|
|
||||
|1|name1|3|1|book3|
|
||||
|2|name2|4|2|book4|
|
||||
|3|name3||||
|
||||
|
||||
|
||||
|
||||
**RIGHT JOIN** (first ∩ Books U Books)
|
||||
Means all of right table and intersection of 2 tables is also included
|
||||
Query
|
||||
```sql
|
||||
SELECT *
|
||||
FROM first
|
||||
RIGHT JOIN Books ON first.id = Books.user_id;
|
||||
```
|
||||
Output
|
||||
|id|name|id|user_id|book_name|
|
||||
|--|----|--|-------|---------|
|
||||
|1|name1|1|1|book1|
|
||||
|1|name1|2|1|book2|
|
||||
|1|name1|3|1|book3|
|
||||
|2|name2|4|2|book4|
|
||||
|||5|4|book5|
|
||||
|
||||
|
||||
|
||||
Triple JOIN
|
||||
Query
|
||||
```sql
|
||||
SELECT h.Address, p.Name, p.Address as OwnerAddress, i.url FROM house AS h
|
||||
INNER JOIN person AS p ON p.personID = h.personID
|
||||
INNER JOIN images AS i ON i.personID = p.personID
|
||||
GROUP BY h.houseID
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
**Some snippets**
|
||||
- query to select those records in which user has login and there session is recorded. Not all users who loginned have their session recorded.
|
||||
Table named `users` have columns `id` as int, `email`
|
||||
Table named `login` have columns like `id` and `email`
|
||||
Table named `sessions` have columns like `id` and `userid` as text
|
||||
Connection between users and login is email and connection between users and sessions is userid. So we need to join these 3 tables as in order to connect `login` and `sessions` we need to connect it with mutual relationship `users`
|
||||
```sql
|
||||
select login.*, sessions.userid from users join login on users.email = login.email
|
||||
join sessions on CAST(users.id as text) = sessions.userid
|
||||
group by login.id, sessions.userid
|
||||
```
|
||||
As sessions.userid is text so we type cased users.id to text when comparing.
|
||||
|
||||
## Keys
|
||||
|
||||
- Adding foriegn key
|
||||
https://www.w3schools.com/sql/sql_foreignkey.asp
|
||||
```sql
|
||||
CREATE TABLE Orders (
|
||||
OrderID int NOT NULL,
|
||||
OrderNumber int NOT NULL,
|
||||
PersonID int,
|
||||
PRIMARY KEY (OrderID),
|
||||
FOREIGN KEY (PersonID) REFERENCES Persons(PersonID)
|
||||
);
|
||||
```
|
||||
here Persons in the other table where Orders.PersonID is referencing to Persons.PersonID
|
||||
Make sure that foreign key dont contain value which is not available in reference table.
|
||||
- preventing delete related records for foreign keys
|
||||
Cascade Delete: This will automatically delete records in table B when the corresponding record in table A is deleted. `ON DELETE CASCADE`
|
||||
```sql
|
||||
CREATE TABLE A (
|
||||
id INT PRIMARY KEY,
|
||||
-- other fields
|
||||
);
|
||||
|
||||
CREATE TABLE B (
|
||||
id INT PRIMARY KEY,
|
||||
a_id INT,
|
||||
-- other fields,
|
||||
FOREIGN KEY (a_id) REFERENCES A(id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
```
|
||||
Set Null: This sets the foreign key in table B to NULL when the referenced record in table A is deleted.
|
||||
`ON DELETE SET NULL`
|
||||
Restrict: This will prevent the deletion of a record in table A if there are any related records in table B.
|
||||
`ON DELETE RESTRICT`. This is default
|
||||
|
||||
- cloning table data or structure
|
||||
- cloning structure only
|
||||
`CREATE TABLE employees_clone LIKE employees;`
|
||||
- cloning structure and data
|
||||
`CREATE TABLE employees_clone AS SELECT * FROM employees;`
|
||||
|
||||
|
||||
Update command
|
||||
```sql
|
||||
UPDATE Customers
|
||||
SET ContactName = 'Alfred Schmidt', City= 'Frankfurt'
|
||||
WHERE CustomerID = 1;
|
||||
```
|
||||
|
||||
|
||||
|
||||
insert elements if not exists
|
||||
```sql
|
||||
INSERT INTO table_name (column1, column2, column3)
|
||||
SELECT 'value1', 'value2', 'value3'
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM table_name
|
||||
WHERE column1 = 'value1' AND column2 = 'value2'
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
update joins
|
||||
https://stackoverflow.com/questions/982919/sql-update-query-using-joins
|
||||
```sql
|
||||
-- Source - https://stackoverflow.com/a/982947
|
||||
-- Posted by gbn, modified by community. See post 'Timeline' for change history
|
||||
-- Retrieved 2026-06-18, License - CC BY-SA 3.0
|
||||
|
||||
UPDATE im
|
||||
SET mf_item_number = gm.SKU --etc
|
||||
FROM item_master im
|
||||
JOIN group_master gm
|
||||
ON im.sku = gm.sku
|
||||
JOIN Manufacturer_Master mm
|
||||
ON gm.ManufacturerID = mm.ManufacturerID
|
||||
WHERE im.mf_item_number like 'STA%' AND
|
||||
gm.manufacturerID = 34
|
||||
|
||||
```
|
||||
if this dont work then using legacy way
|
||||
```js
|
||||
const updateQuery = `update ${songDataTableEnums.tablename} as sd
|
||||
set ${songDataTableEnums.columns.is_bookmarked}=${bookmark_value}
|
||||
where exists (
|
||||
select 1
|
||||
from ${keywordTableEnums.tablename} as k
|
||||
where sd.${songDataTableEnums.columns.id} = k.${keywordTableEnums.columns.song_id}
|
||||
and k.${keywordTableEnums.columns.keywords}=?
|
||||
)`
|
||||
```
|
||||
27
joplin notion extension/Web Development/sql/extras.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
extras
|
||||
|
||||
- pocketbase : for small projects
|
||||
- Conflict-Free Replicated Data Type: A conflict-free replicated data type (CRDT) is a special distributed data structure that lets multiple computers store, update, and sync copies of data independently without needing a central coordinator or locking mechanism
|
||||
- last write wins
|
||||
|
||||
```txt
|
||||
there is a table name tab and it contains a column name col.
|
||||
|
||||
now this database is in both devices and is same too. values in column 'col' of table 'tab' in both database are A.B,C which is last modified at 5pm
|
||||
|
||||
in device1 changes being made and now its value is X,B . this database is last updated at 6pm
|
||||
in device2 changes being made and now its value is Y,C. this database is last updated at 7pm
|
||||
|
||||
now how to sync the changes?
|
||||
in first one, A is replaced with X, C is deleted
|
||||
in 2nd one, A is replaced with Y, B is deleted
|
||||
|
||||
so total changes are
|
||||
A -> X
|
||||
C -> gone
|
||||
A -> Y
|
||||
B -> gone
|
||||
|
||||
here A being updated to either X and Y is decided by time so latest one ie 7pm one win and A->Y, B and C are deleted
|
||||
so finally it will be Y
|
||||
```
|
||||
190
joplin notion extension/Web Development/sql/mysql.md
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
|
||||
- MariaDB
|
||||
https://www.mariadbtutorial.com/getting-started/connect-to-mariadb/
|
||||
|
||||
After installing mariaDB use this command to setup database directory
|
||||
`mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql`
|
||||
do this `rm -rf /var/lib/mysql/*` to undo this initialization process
|
||||
|
||||
To start mariadbd at boot time you have to copy
|
||||
**support-files/mariadb.service** to the right place for your system
|
||||
U can do this in systemd init system with
|
||||
`systemctl enable --now mariadb.service`
|
||||
|
||||
|
||||
Two all-privilege accounts were created.
|
||||
One is **root@localhost**, it has no password, but you need to
|
||||
be system 'root' user to connect. Use, for example, `sudo mysql`
|
||||
The second is **mysql@localhost**, it has no password either, but
|
||||
you need to be the system 'mysql' user to connect.
|
||||
After connecting you can set the password, if you would need to be
|
||||
able to connect as any of these users with a password and without sudo
|
||||
|
||||
See the MariaDB Knowledgebase at https://mariadb.com/kb
|
||||
|
||||
You can start the MariaDB daemon with:
|
||||
`cd '/usr' ; /usr/bin/mariadb-safe --datadir='/var/lib/mysql'`
|
||||
|
||||
You can test the MariaDB daemon with mariadb-test-run.pl
|
||||
`cd '/usr/mariadb-test' ; perl mariadb-test-run.pl`
|
||||
|
||||
Please report any problems at https://mariadb.org/jira
|
||||
|
||||
The latest information about MariaDB is available at https://mariadb.org/.
|
||||
|
||||
Consider joining MariaDB's strong and vibrant community:
|
||||
https://mariadb.org/get-involved/
|
||||
|
||||
- More
|
||||
To load mysql shell in command prompt:
|
||||
|
||||
`mysql -u root -p`
|
||||
Here root is owner_name. This will prompt for password which is ‘password’.
|
||||
or
|
||||
`mysql -h localhost -P 3306 -u root -p test`
|
||||
|
||||
- To connect to remote mysql
|
||||
To connect to MariaDB on a specific host, you use the -h option:
|
||||
|
||||
`mysql -u [username] -p[password] -h [hostname]`
|
||||
or to disable ssl check when connecting
|
||||
`mysql --skip-ssl -u proj1_wishrocky -P 3306 -p94db734d1935c57ac05eab8987a959c98f074706 -h r77rn.h.filess.io proj1_wishrocky`
|
||||
or (for newer versions)
|
||||
` mysql --ssl-mode=DISABLED -u proj1_wishrocky -P 3306 -p94db734d1935c57ac05eab8987a959c98f074706 -h r77rn.h.filess.io proj1_wishrocky`
|
||||
|
||||
|
||||
|
||||
To get list of database:
|
||||
|
||||
`show databases;`
|
||||
|
||||
To create database
|
||||
```sql
|
||||
drop database if exists database_name;
|
||||
create database database_name;
|
||||
```
|
||||
|
||||
To load database
|
||||
|
||||
`use hospitals;`
|
||||
|
||||
hospitals here is name of database
|
||||
|
||||
Once database is loaded, to get list of tables:
|
||||
|
||||
`show tables;`
|
||||
|
||||
To get schema of tables:
|
||||
|
||||
`desc patients;` or `describe patients;`
|
||||
|
||||
where patients is name of table
|
||||
|
||||
- To create table
|
||||
```sql
|
||||
drop table if exists table_name;
|
||||
create table table_name(....);
|
||||
```
|
||||
|
||||
- Creating table
|
||||
|
||||
```sql
|
||||
create table project (
|
||||
emp_id int not null,
|
||||
id int not null,
|
||||
name varchar(30),
|
||||
location varchar(40),
|
||||
primary key(emp_id)
|
||||
);
|
||||
```
|
||||
- Adding Auto increment
|
||||
- SERIAL is an alias for BIGINT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE.
|
||||
|
||||
```sql
|
||||
-- To let the AUTO_INCREMENT sequence start with another value, use the following SQL statement:
|
||||
ALTER TABLE Persons AUTO_INCREMENT=100;
|
||||
|
||||
alter table employee
|
||||
modify emp_id int not null auto_increment;
|
||||
```
|
||||
- Change mysql password if forget
|
||||
- Stop mysql service
|
||||
`sudo systemctl stop mysql`
|
||||
- start it in safe mode
|
||||
`sudo mysqld_safe --skip-grant-tables --skip-networking`
|
||||
- Then in other terminal type
|
||||
`mysql -u root`
|
||||
- when in mysql shell
|
||||
`FLUSH PRIVILEGES;`
|
||||
`ALTER USER 'root'@'localhost' IDENTIFIED BY 'new_password';`
|
||||
- close the terminal of the safe mode and start mysql service again
|
||||
`sudo systemctl start mysql`
|
||||
- running sql script in mysql
|
||||
`mysql -u username -p`
|
||||
then
|
||||
`SOURCE /path/to/your/script.sql;`
|
||||
Alternatively, you can execute the script directly from the command line without entering the MySQL shell
|
||||
`mysql -u username -p < /path/to/your/script.sql`
|
||||
- if else use in mysql
|
||||
```sql
|
||||
SET @primaryKeyValue = 13; /* Your primary key value here */
|
||||
|
||||
IF EXISTS (SELECT 1 FROM TableB WHERE foreignKeyColumn = @primaryKeyValue) THEN
|
||||
-- Update the record in TableA
|
||||
UPDATE TableA
|
||||
SET someField = 'newValue' -- Set your field and value accordingly
|
||||
WHERE primaryKeyColumn = @primaryKeyValue;
|
||||
ELSE
|
||||
-- Delete the record in TableA
|
||||
DELETE FROM TableA
|
||||
WHERE primaryKeyColumn = @primaryKeyValue;
|
||||
END IF;
|
||||
|
||||
```
|
||||
- creating and using procedures
|
||||
```sql
|
||||
-- to replace semicolon with // for procedures
|
||||
DELIMITER //
|
||||
|
||||
CREATE PROCEDURE if not EXISTS UpdateOrDeleteQuestion(IN primaryKeyValue INT)
|
||||
BEGIN
|
||||
IF EXISTS (SELECT 1 FROM quiz_questions WHERE questionID = primaryKeyValue) THEN
|
||||
-- Update the record in questions
|
||||
UPDATE questions
|
||||
SET isDeleted = TRUE
|
||||
WHERE id = primaryKeyValue;
|
||||
ELSE
|
||||
-- Delete the record in questions
|
||||
DELETE FROM questions
|
||||
WHERE id = primaryKeyValue;
|
||||
END IF;
|
||||
END //
|
||||
|
||||
DELIMITER ;
|
||||
|
||||
-- Now you can call the procedure with the primary key value
|
||||
CALL UpdateOrDeleteQuestion(2);
|
||||
-- to delete it
|
||||
drop procedure UpdateOrDeleteQuestion;
|
||||
```
|
||||
|
||||
- to run mysql in docker first setup `/var/lib/mysql` by
|
||||
`mysql_install_db --user=root --basedir=/usr --datadir=/var/lib/mysql`
|
||||
then
|
||||
```bash
|
||||
mysqld_safe --user=root &
|
||||
|
||||
# Wait for MySQL to initialize (this is important)
|
||||
sleep 5
|
||||
|
||||
# other scripts to start (like backend services)
|
||||
# npm start
|
||||
```
|
||||
in order to check if mysql is listening on localhost:3306 try this
|
||||
`netstat -tuln | grep 3306`
|
||||
|
||||
|
||||
|
||||
|id|username|discriminator|avatar|accent_color|banner|theme_colors|pronouns|phone|desktop|mobile|premium|premium_type|bot|bio|system|nsfw_allowed|mfa_enabled|totp_secret|totp_last_ticket|created_at|premium_since|verified|disabled|deleted|email|flags|public_flags|purchased_flags|premium_usage_flags|rights|data|fingerprints|settingsIndex|webauthn_enabled|badge_ids|avatar_decoration_data|display_name_styles|collectibles|primary_guild|
|
||||
|--|--------|-------------|------|------------|------|------------|--------|-----|-------|------|-------|------------|---|---|------|------------|-----------|-----------|----------------|----------|-------------|--------|--------|-------|-----|-----|------------|---------------|-------------------|------|----|------------|-------------|----------------|---------|----------------------|-------------------|------------|-------------|
|
||||
|1471020127947448357|qwerty|3217|68d3b54bae93fdb947e64cb7df2584c5||c587b1be12f1491329d90359d89dc6bf||||false|false|true|2|false||false|true|false|||2026-02-11 11:18:48.735|2026-02-11 11:18:48.735|true|false|false|qwerty@email.com|0|0|0|0|875069521787904|{"hash":"$2b$12$I4fHr7GfGjbVttWsYFdZXue0uN2DMeSKbSAzu77JdZWS7fS4iJUsC","valid_tokens_since":"2026-02-11T05:48:48.735Z"}||1|false||||||
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
postgresql syntax
|
||||
|
||||
- Creating table
|
||||
```sql
|
||||
DROP TABLE IF EXISTS COMPANY;
|
||||
CREATE TABLE COMPANY(
|
||||
ID INT PRIMARY KEY NOT NULL,
|
||||
NAME TEXT NOT NULL,
|
||||
AGE INT NOT NULL,
|
||||
ADDRESS CHAR(50),
|
||||
SALARY REAL
|
||||
);
|
||||
```
|
||||
For auto increment
|
||||
```sql
|
||||
CREATE TABLE COMPANY(
|
||||
ID SERIAL PRIMARY KEY NOT NULL,
|
||||
NAME TEXT NOT NULL,
|
||||
AGE INT NOT NULL,
|
||||
ADDRESS CHAR(50),
|
||||
SALARY REAL
|
||||
);
|
||||
```
|
||||
|
||||
`SERIAL` for auto increment
|
||||
- to load postgresql database
|
||||
|
||||
```bash
|
||||
psql -U postgres smart-brain
|
||||
```
|
||||
|
||||
Here postgres is owner name and smart-brain is name of data base. It will prompt for password which is U2FsdGVkX1/k+uOTLs4gSYVmxYAJEQybNVGnxIQVHyg=. Refer to
|
||||
|
||||
[Web development](../../../undefined)
|
||||
|
||||
for decrypting it.
|
||||
|
||||
To load postgresql without database:
|
||||
|
||||
`psql -U postgres`
|
||||
|
||||
To create database:
|
||||
|
||||
`createdb mydb -U postgres`
|
||||
|
||||
or
|
||||
|
||||
```bash
|
||||
psql -U postgres
|
||||
create database mydb;
|
||||
```
|
||||
|
||||
To get list of database:
|
||||
|
||||
`\l`
|
||||
|
||||
To connect to database when login as user
|
||||
|
||||
`\connect dbname`
|
||||
|
||||
`\q`: To quit
|
||||
- List tables, views and sequences
|
||||
`\d`
|
||||
- Describe tables
|
||||
`\d <table_name>`
|
||||
240
joplin notion extension/Web Development/sql/postgresql.md
Normal file
|
|
@ -0,0 +1,240 @@
|
|||
postgresql
|
||||
|
||||
- Installation
|
||||
https://www.geeksforgeeks.org/how-to-install-postgresql-on-arch-based-linux-distributions-manjaro/
|
||||
https://gist.github.com/NickMcSweeney/3444ce99209ee9bd9393ae6ab48599d8
|
||||
- To use it
|
||||
`sudo su - postgres`
|
||||
or
|
||||
`psql -U postgres`
|
||||
Creating database when in user
|
||||
`create database <database_name>`
|
||||
delete database
|
||||
`drop database <database_name>`
|
||||
- Remote connection
|
||||
`psql -U postgres -p 5432 -h hostname` (5432 is default postgresql port number)
|
||||
or
|
||||
`psql -U postgres -p 5432 -h hostname -d database_name`
|
||||
-U is username
|
||||
-p for port
|
||||
-h for hostname
|
||||
-d for database name
|
||||
|
||||
To directly connect with url
|
||||
`psql postgres://user:password@ip_add_or_domain:port/db_name`
|
||||
or
|
||||
`PGPASSWORD="your_password" psql -U your_username -d your_database -h your_host`
|
||||
- Import and export
|
||||
Exporting postgresql Database
|
||||
We need to create a dump file. Here smart-brain is name of database
|
||||
`pg_dump -U postgres smart-brain > dump.sql`
|
||||
for remote
|
||||
`pg_dump -U postgres -p 5432 -h hostname -d database_name > dump.sql`
|
||||
|
||||
Importing postgresql Database
|
||||
`psql -U postgres smart-brain < dump.sql`
|
||||
|
||||
for archive compressed backups and restore
|
||||
backup
|
||||
` pg_dump -U synapse_user -p 5432 -h localhost -d -Fc synapse > synapse_backup1.dump`
|
||||
restore
|
||||
`pg_restore -U synapse_user -p 5432 -h localhost -d synapse1 synapse_backup1.dump`
|
||||
- Store query output in a file
|
||||
`psql -d DatabaseName -U UserName -c "SELECT * FROM TABLE" -o /root/Desktop/file.txt`
|
||||
Saving query output in csv file
|
||||
https://stackoverflow.com/questions/1517635/save-pl-pgsql-output-from-postgresql-to-a-csv-file
|
||||
By using a meta command `\copy`
|
||||
`\copy (Select * From foo) To '/tmp/test.csv' With CSV DELIMITER ',' HEADER`
|
||||
- Sometimes there is a error `current transaction is aborted, commands ignored until end of transaction block` then run this query
|
||||
`commit;` to fix this
|
||||
|
||||
insert only if the record with paricular value dont exist
|
||||
|
||||
here unique_column is column with must have unique constraint. it must be a key
|
||||
```sql
|
||||
INSERT INTO table_name (column1, column2)
|
||||
VALUES (val1, val2)
|
||||
ON CONFLICT (unique_column) DO NOTHING;
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
- set password of postgres user
|
||||
`ALTER USER username WITH PASSWORD 'newpassword';`
|
||||
|
||||
# Setup Postgresql
|
||||
> run postgresql with systemctl
|
||||
|
||||
### Install postgres
|
||||
|
||||
##### latest
|
||||
`sudo pacman -S postgresql`
|
||||
|
||||
##### specific version
|
||||
> find version & build from source
|
||||
|
||||
### Check version
|
||||
`postgres --version`
|
||||
|
||||
### Confirm psql is not running
|
||||
`sudo systemctl status postgresql` --> should not be running
|
||||
|
||||
### Login as the postgres user
|
||||
> Note: always do this any time you are doing any type of admin work on psql
|
||||
|
||||
`sudo su - postgres`
|
||||
|
||||
### Initialize data directory
|
||||
> Note: default db for psql is /var/lib/postgres/data
|
||||
|
||||
`initdb --locale en_US.UTF-8 -D /var/lib/postgres/data`
|
||||
|
||||
### Logout of **postgres** user
|
||||
`exit`
|
||||
|
||||
### Confirm psql is still not running
|
||||
`sudo systemctl status postgresql` --> should not be running
|
||||
|
||||
### Start psql
|
||||
`sudo systemctl start postgresql`
|
||||
|
||||
### Confirm psql is running
|
||||
`sudo systemctl status postgresql` --> should be active
|
||||
|
||||
## Create user
|
||||
|
||||
### Log into postgres
|
||||
`sudo su - postgres`
|
||||
|
||||
### Create a new user
|
||||
> Note: user can be called anything however if you create a PostgreSQL user with the same name as your Linux username, it allows you to access the PostgreSQL database shell without having to specify a user to login (which makes it quite convenient).
|
||||
|
||||
`createuser --interactive`
|
||||
or
|
||||
`sudo -u postgres bash`
|
||||
`createuser --pwprompt synapse_user`
|
||||
and for db
|
||||
`createdb --encoding=UTF8 --locale=C --template=template0 --owner=synapse_user synapse`
|
||||
|
||||
- Enter name of role to add: `MY_LINUX_USERNAME` (add youur linux user else psql command wont work when using with that user )
|
||||
- Shall the new role be a superuser?: `y`
|
||||
|
||||
### Logout of **postgres** user
|
||||
`exit`
|
||||
|
||||
### Restart psql
|
||||
`sudo systemctl restart postgresql`
|
||||
|
||||
### Confirm psql is running
|
||||
> Note: can see that it was restarted by looking at the timestamp on the ***Active*** field
|
||||
|
||||
`sudo systemctl status postgresql`
|
||||
|
||||
|
||||
### Managing users
|
||||
To login as a newly created user in PostgreSQL, you typically need to use a client or interface that supports PostgreSQL, such as `psql`, PgAdmin, or another tool that allows database interaction. Here's how you can do it using `psql`, the command-line tool for PostgreSQL.
|
||||
|
||||
1. **Create the User**: First, you need to create the user (if you haven't done so already). You can do this by connecting to your PostgreSQL instance as a superuser (often `postgres`) and running a command like the following:
|
||||
First type
|
||||
`psql -U postgres`
|
||||
```sql
|
||||
CREATE USER my_new_user WITH PASSWORD 'password';
|
||||
```
|
||||
|
||||
Adjust `my_new_user` and `'password'` according to your preferences.
|
||||
|
||||
2. **Grant Permissions** (if needed): Depending on what you want this user to do, you'll likely need to grant them some permissions or access to a database. Here's an example of how you can grant all privileges on a database named `my_database` to your new user:
|
||||
|
||||
```sql
|
||||
GRANT ALL PRIVILEGES ON DATABASE my_database TO my_new_user;
|
||||
```
|
||||
|
||||
3. **Login Using `psql`**: To login as the new user from the command line using `psql`, you would use a command like this:
|
||||
|
||||
```bash
|
||||
psql -d my_database -U my_new_user -W
|
||||
```
|
||||
|
||||
- `-d my_database` specifies the database you are connecting to.
|
||||
- `-U my_new_user` specifies the user you are logging in as.
|
||||
- `-W` prompts `psql` to ask for the password of the user. (Note: For security reasons, it's recommended to use `-W` to prompt for the password instead of passing it directly in the command line.)
|
||||
|
||||
4. **Enter the Password**: After executing the above command, you'll be prompted to enter the password for `my_new_user`. Enter the password you have set for this account, and you should be logged in.
|
||||
|
||||
5. **Using Other Tools**: If you are using a GUI-based tool like PgAdmin, the process involves:
|
||||
|
||||
- Open PgAdmin and connect to your PostgreSQL server.
|
||||
- Create a new server connection if your user has access to a different server or database.
|
||||
|
||||
|
||||
|
||||
- To delete users
|
||||
`drop user <username>`
|
||||
|
||||
- Adding password for local connections
|
||||
By default there is `trust` authentication flag in `pg_hba.conf` file so we can login without requiring password. To change that just change trust to md5
|
||||
Location of `pg_hba.conf` : `/var/lib/postgres/data/pg_hba.conf`
|
||||
Other authenticaor flags are
|
||||
- trust allows the connection without a password.
|
||||
- peer uses the operating system user identity to authenticate (common for local connections).
|
||||
- md5 or scram-sha-256 require a password
|
||||
- Changing password
|
||||
`alter user tpost with password 'qwerty';`
|
||||
|
||||
|
||||
- Schema public permission error
|
||||
When creating table u may get error like
|
||||
`ERROR: permission denied for schema public`
|
||||
Then login to superuser ie `postgres`
|
||||
then run this
|
||||
`GRANT USAGE ON SCHEMA public TO tpost;`
|
||||
to grant permission
|
||||
Then restart the postgresql service
|
||||
|
||||
- running sql script in postgresql
|
||||
`psql -U username -d database_name`
|
||||
then
|
||||
`\i /path/to/your/script.sql;`
|
||||
Alternatively, you can execute the script directly from the command line without entering the MySQL shell
|
||||
`psql -U username -d database_name -f /path/to/your/script.sql`
|
||||
|
||||
|
||||
in debian
|
||||
https://neon.tech/postgresql/postgresql-getting-started/install-postgresql-linux#connect-to-the-postgresql-database-server
|
||||
use this to login to psql
|
||||
`sudo -u postgres psql`
|
||||
or
|
||||
```sh
|
||||
sudo -i -u postgres
|
||||
# then
|
||||
psql
|
||||
```
|
||||
or
|
||||
`psql -U postgres -p 5432 -h localhost`
|
||||
for non interactive password use
|
||||
`PGPASSWORD=PASS psql -U postgres -p 5432 -h localhost` or `psql postgresql://postgres:PASS@localhost:5432`
|
||||
|
||||
|
||||
check database
|
||||
Many ways. Du -sh the folder. Dbdump the database, and there's a psql command for all the statistics too
|
||||
SELECT pg_size_pretty(pg_total_relation_size('"<schema>"."
|
||||
or
|
||||
for specific database
|
||||
`SELECT pg_size_pretty(pg_database_size('your_database_name'));`
|
||||
shortcut
|
||||
`\l+ your_database_name`
|
||||
|
||||
for all database
|
||||
```sql
|
||||
SELECT datname AS database_name,
|
||||
pg_size_pretty(pg_database_size(datname)) AS size
|
||||
FROM pg_database
|
||||
ORDER BY pg_database_size(datname) DESC;
|
||||
|
||||
```
|
||||
shortcut
|
||||
`\l+`
|
||||
https://stackoverflow.com/questions/2596624/how-do-you-find-the-disk-size-of-a-postgres-postgresql-table-and-its-indexes
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
psql peer authetication error
|
||||
|
||||
**by llm**
|
||||
Ah, the **"Peer authentication failed for user"** error typically occurs because PostgreSQL is using **peer authentication**, which means it tries to authenticate you based on your OS username (the user you're logged in as) rather than with a password.
|
||||
|
||||
In this case, your system username doesn’t match the `postgres` user, so PostgreSQL is rejecting the connection.
|
||||
|
||||
To fix this, you can change the authentication method in PostgreSQL’s `pg_hba.conf` file to use **password authentication** (or any other method you prefer).
|
||||
|
||||
Here’s how you can fix this:
|
||||
|
||||
### 1. **Edit `pg_hba.conf` file**
|
||||
|
||||
The first thing you need to do is modify the PostgreSQL authentication settings to allow password-based authentication.
|
||||
|
||||
* Find the location of the `pg_hba.conf` file. It’s typically in one of these locations:
|
||||
|
||||
* `/etc/postgresql/<version>/main/pg_hba.conf` (on Debian-based systems like Ubuntu)
|
||||
* `/var/lib/pgsql/data/pg_hba.conf` (on Red Hat/CentOS/Fedora systems)
|
||||
|
||||
* Open the `pg_hba.conf` file using a text editor like `nano` or `vim`:
|
||||
|
||||
```bash
|
||||
sudo nano /etc/postgresql/<version>/main/pg_hba.conf
|
||||
```
|
||||
|
||||
OR
|
||||
|
||||
```bash
|
||||
sudo nano /var/lib/pgsql/data/pg_hba.conf
|
||||
```
|
||||
|
||||
### 2. **Change authentication method**
|
||||
|
||||
Look for lines that look something like this (for local connections):
|
||||
|
||||
```plaintext
|
||||
local all postgres peer
|
||||
```
|
||||
|
||||
This means PostgreSQL is using **peer authentication** for the `postgres` user when connecting locally.
|
||||
|
||||
Change the `peer` method to `md5` (password authentication):
|
||||
|
||||
```plaintext
|
||||
local all postgres md5
|
||||
```
|
||||
|
||||
This will require a password for the `postgres` user.
|
||||
|
||||
### 3. **Reload PostgreSQL**
|
||||
|
||||
After making the changes, you need to reload PostgreSQL to apply them:
|
||||
|
||||
```bash
|
||||
sudo systemctl reload postgresql
|
||||
```
|
||||
|
||||
### 4. **Set a password for the `postgres` user**
|
||||
|
||||
If you haven’t already set a password for the `postgres` user, do so by logging in as `postgres`:
|
||||
|
||||
```bash
|
||||
sudo -u postgres psql
|
||||
```
|
||||
|
||||
Then, inside the `psql` shell, run:
|
||||
|
||||
```sql
|
||||
ALTER USER postgres PASSWORD 'your_password';
|
||||
```
|
||||
|
||||
Replace `'your_password'` with the password you want to set.
|
||||
|
||||
### 5. **Try connecting again**
|
||||
|
||||
Now you should be able to connect using `psql -U postgres` with the password:
|
||||
|
||||
```bash
|
||||
psql -U postgres -h localhost
|
||||
```
|
||||
|
||||
You will be prompted for the password you just set.
|
||||
|
||||
---
|
||||
|
||||
### Recap:
|
||||
|
||||
1. Modify `pg_hba.conf` to use `md5` instead of `peer` for `postgres` user.
|
||||
2. Reload PostgreSQL.
|
||||
3. Set a password for the `postgres` user.
|
||||
4. Try connecting again using `psql -U postgres`.
|
||||
|
||||
Let me know if this works or if you're still running into any issues!
|
||||
62
joplin notion extension/Web Development/sql/sqlite.md
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
sqlite
|
||||
|
||||
- get list of databases : `.database` or `.databases`
|
||||
- get list of tables : `.tables`
|
||||
- get schemas : `.schema` , for particular table : `schema <TABLE_NAME>`
|
||||
- to show field name when using select query, make sure to switch headers on by `.headers on`
|
||||
|
||||
|
||||
ddl commands
|
||||
|
||||
**alter tables**
|
||||
- `ALTER TABLE old_table_name RENAME TO new_table_name;`
|
||||
- `ALTER TABLE table_name RENAME COLUMN old_column_name TO new_column_name;`
|
||||
- `ALTER TABLE table_name ADD COLUMN column_name datatype;`
|
||||
- `ALTER TABLE table_name DROP COLUMN column_name;`
|
||||
- `ALTER TABLE songdata add COLUMN is_bookmarked INTEGER DEFAULT 0`
|
||||
- `ALTER TABLE Employees ALTER COLUMN Status SET DEFAULT 'Active'` (requires new version)
|
||||
- `ALTER TABLE ... ALTER COLUMN ... DROP NOT NULL` (requires new version)
|
||||
**create tables**
|
||||
- foreign key constraint
|
||||
`FOREIGN KEY (lyrics_url) REFERENCES lyricsUrl(lyrics_url)`
|
||||
|
||||
|
||||
dml ones
|
||||
|
||||
**timestamp**
|
||||
https://www.sqlite.org/lang_datefunc.html
|
||||
```sql
|
||||
CREATE TABLE event_log (
|
||||
id INTEGER PRIMARY KEY,
|
||||
event_name TEXT,
|
||||
|
||||
-- Option A: Stores as human-readable TEXT (UTC time)
|
||||
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
-- Option B: Stores as a Unix INTEGER timestamp (Seconds since 1970)
|
||||
unix_timestamp INTEGER DEFAULT (strftime('%s', 'now'))
|
||||
);
|
||||
```
|
||||
|
||||
```sql
|
||||
insert into event_log (id,event_name, unix_timestamp)
|
||||
values(1,'event1',unixepoch());
|
||||
```
|
||||
|
||||
|
||||
|
||||
upsert
|
||||
```sql
|
||||
INSERT INTO table_name (column1, column2)
|
||||
VALUES (value1, value2)
|
||||
ON CONFLICT (conflict_column)
|
||||
DO UPDATE SET column1 = excluded.column1, column2 = excluded.column2;
|
||||
```
|
||||
|
||||
|
||||
|
||||
auto increment
|
||||
only possible for integer columns declared as primary key
|
||||
```sql
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
```
|
||||
26
joplin notion extension/Web Development/windows/Extras.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
Extras
|
||||
|
||||
- godmode tools access
|
||||
https://files.catbox.moe/kt7vx3.mp4
|
||||
- recuva : recover deleted files
|
||||
- https://github.com/HickerDicker/SapphireTool/ : post installation tool for windows 10 and 11
|
||||
- bulk crap uninstaller : to uninstall windows bloat
|
||||
-  : for running win 7/10 apps on win xp.
|
||||
- Removing bloatware : NTLite
|
||||
- SaphireOS : custom window iso
|
||||
https://github.com/HickerDicker/SapphireOS
|
||||
- download unbloated windows
|
||||
https://massgrave.dev/windows_ltsc_links
|
||||
to debloat use this, download from here : https://github.com/Sycnex/Windows10Debloater
|
||||
[Windows10Debloater-master.zip](../../../_resources/Windows10Debloater-master.zip)
|
||||
- to activate them
|
||||
https://massgrave.dev/
|
||||
[window_activation_script.txt](:/c1e7e49ba1244eb79ea28a42b139897a)
|
||||
it also contains for office along with windows
|
||||
- tablacus explorer
|
||||
https://github.com/tablacus/TablacusExplorer
|
||||
[TablacusExplorer-master.zip](:/74bc3a0b3a354a009a262ead1c66a644)
|
||||
- win 10 installation driver not found issue
|
||||
https://www.youtube.com/watch?v=Ode1010Sr5w
|
||||
- windows automatically install new drivers (better than windows inbuilt device manager)
|
||||
snappy driver installer origin
|
||||
4
joplin notion extension/Web Development/windows/Info.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
Info
|
||||
|
||||
- ssd mount id
|
||||
2ADE4C3EDE4C0493
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
Resources
|
||||
|
||||
- memreduct : Free RAM
|
||||
|
||||
|
||||
[memreduct-3.4-bin.zip](../../../_resources/memreduct-3.4-bin.zip)
|
||||
|
||||
8
joplin notion extension/Web Development/windows/cons.md
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
cons
|
||||
|
||||
windows 11
|
||||
- still have so many questionable design choices
|
||||
- ads and bloats
|
||||
- taskbar not showing the whole menu unless right clicking on the windows icon
|
||||
- requires tlp
|
||||
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
disable windows updates
|
||||
https://www.youtube.com/watch?v=6atgKRQjsKA
|
||||
https://small.fileditchstuff.me/s4/HQgTZTMGJAYMmhYmTGk.mp4
|
||||
How to Disable Windows Updates on Windows 10 11 Permanently 100% works guaranteed 2024.mp4 https://files.catbox.moe/lry40b.mp4
|
||||
|
||||
|
||||
- Need to disable 3 services ie `WaasmedicSvc`, `UsoSvc` and `wuauserv` properly using registry editor. make sure to export registry editor first in case things go south
|
||||
- try using winutil
|
||||
run this in powershell
|
||||
`iwr -useb https://christitus.com/win | iex`
|
||||
it is a script for a lot of stuff like debloating, disabling updates, etc.
|
||||
- also this
|
||||
https://www.sordum.org/9470/windows-update-blocker-v1-8/
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
issues
|
||||
|
||||
- removing cors surrogate
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
remove auth keys
|
||||
|
||||
**by llm**
|
||||
|
||||
What you’re seeing is normal Windows behavior. **Uninstalling an app does not always remove user data**, and Windscribe keeps a small amount of account info so it can restore your session.
|
||||
|
||||
On Windows, Windscribe can remember your username via **one (or more) of these places**:
|
||||
|
||||
---
|
||||
|
||||
## 1. AppData folders (most common)
|
||||
|
||||
These folders are **not deleted** when you uninstall most apps.
|
||||
|
||||
Check both:
|
||||
|
||||
```
|
||||
C:\Users\<your-username>\AppData\Roaming\Windscribe
|
||||
C:\Users\<your-username>\AppData\Local\Windscribe
|
||||
```
|
||||
|
||||
(You can paste these into File Explorer’s address bar.)
|
||||
|
||||
These may contain:
|
||||
|
||||
* Config files
|
||||
* Cached account info
|
||||
* Login tokens (not your password in plain text)
|
||||
|
||||
---
|
||||
|
||||
## 2. Windows Registry
|
||||
|
||||
Windscribe also stores settings under your user registry hive.
|
||||
|
||||
Common locations:
|
||||
|
||||
```
|
||||
HKEY_CURRENT_USER\Software\Windscribe
|
||||
HKEY_LOCAL_MACHINE\Software\Windscribe
|
||||
```
|
||||
|
||||
The **username is often stored here**, which is why it reappears after reinstall.
|
||||
|
||||
---
|
||||
|
||||
## 3. Windows Credential Manager (very likely)
|
||||
|
||||
Windscribe may store a login token here so you don’t have to re-authenticate.
|
||||
|
||||
Open:
|
||||
|
||||
```
|
||||
Control Panel → Credential Manager → Windows Credentials
|
||||
```
|
||||
|
||||
Look for entries named:
|
||||
|
||||
* Windscribe
|
||||
* Windscribe VPN
|
||||
* WindscribeService
|
||||
|
||||
If present, this is enough for the app to recognize your account.
|
||||
|
||||
---
|
||||
|
||||
## 4. ProgramData (less common, but possible)
|
||||
|
||||
```
|
||||
C:\ProgramData\Windscribe
|
||||
```
|
||||
|
||||
This folder is hidden by default.
|
||||
|
||||
---
|
||||
|
||||
## Why uninstall doesn’t remove it
|
||||
|
||||
Windows uninstallers usually **preserve user data on purpose** so:
|
||||
|
||||
* Settings are kept if you reinstall
|
||||
* You don’t accidentally lose preferences
|
||||
|
||||
This is standard behavior, not Windscribe being sneaky.
|
||||
|
||||
---
|
||||
|
||||
## How to completely remove Windscribe data
|
||||
|
||||
If you want a **truly clean reinstall**:
|
||||
|
||||
1. Uninstall Windscribe normally
|
||||
2. Reboot
|
||||
3. Delete these folders (if they exist):
|
||||
|
||||
```
|
||||
%AppData%\Windscribe
|
||||
%LocalAppData%\Windscribe
|
||||
C:\ProgramData\Windscribe
|
||||
```
|
||||
4. Open **Credential Manager** and remove Windscribe entries
|
||||
5. (Optional) Remove registry keys:
|
||||
|
||||
```
|
||||
HKCU\Software\Windscribe
|
||||
```
|
||||
6. Reboot again
|
||||
7. Reinstall
|
||||
|
||||
After that, Windscribe should **not remember your username**.
|
||||
|
||||
---
|
||||
|
||||
If you want, I can also explain **exactly which file/registry value stores the username** and what format it’s in, or help you verify which one is being used on your system.
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
softwares setups
|
||||
|
||||
- office 2010
|
||||
https://www.mediafire.com/file/73otjz8ikpir8w7/office10-20240326T134652Z-001.zip/file
|
||||
|
|
@ -0,0 +1,242 @@
|
|||
Arch Installation in usb flash drive
|
||||
|
||||
Arch Installation for a removable USB flash drive:
|
||||
|
||||
|
||||
-> Installing on a 64-bit UEFI non-CSM system.
|
||||
-> using GPT partition style.
|
||||
|
||||
Requirements:
|
||||
|
||||
-> A USB flash drive with bootable arch linux installation media.
|
||||
-> Another USB where linux is going to be installed, recommended size: 32 GB.
|
||||
-> A desktop computer or laptop for installing arch which supports UEFI.
|
||||
|
||||
Pre-Installation:
|
||||
|
||||
1. Insert both of the USB flash drive.
|
||||
2. Boot from the USB with the arch installation media.
|
||||
|
||||
Follow along in the next unit for installing arch on the USB flash drive.
|
||||
|
||||
Installation:
|
||||
|
||||
1. Connect to the internet either by ethernet or wifi.
|
||||
|
||||
-> For wifi, use the iwctl utility.
|
||||
-> Open it using the 'iwctl' command.
|
||||
|
||||
root@archiso~# iwctl
|
||||
|
||||
-> inside it, get the list of all the network devices using the following command.
|
||||
|
||||
[iwd]# device list
|
||||
|
||||
-> Use the wireless adapter to get scan and get a list of all the available networks.
|
||||
|
||||
[iwd]# station <device> scan
|
||||
[iwd]# station <device> get-networks
|
||||
|
||||
-> Connecting to the wireless network.
|
||||
|
||||
[iwd]# station <device> connect <netowrk_name>
|
||||
|
||||
-> Enter the passphrase and check for connectivity using the following.
|
||||
|
||||
[iwd]# station <device> show
|
||||
|
||||
-> if connected, use the 'exit' command to exit the utility.
|
||||
|
||||
2. Check you internet connectivity using the following.
|
||||
|
||||
root@archiso~# ping <URL>
|
||||
|
||||
3. Update the system clock.
|
||||
|
||||
root@archiso~# timedatectl set-ntp true
|
||||
|
||||
4. List all the disks.
|
||||
|
||||
root@archiso~# lsblk
|
||||
|
||||
-> disks are in the format of /dev/sd<x>.
|
||||
-> Here, recognise the USB drive disk where arch has to be installed.
|
||||
|
||||
5. Partition the disks.
|
||||
|
||||
-> Use the gdisk/ fdisk/ cfdisk command for partitioning the disk.
|
||||
eg. gdisk /dev/sd<x>
|
||||
|
||||
-> In this tutorial, I am using 3 partitions for the Linux EFI system, swap and the root.
|
||||
-> Here, <x> denotes the disk letter.
|
||||
|
||||
-> Recommended sizes for partitions:
|
||||
|
||||
(i) /dev/sd<x>1 -> EFI Partition: 550M
|
||||
(ii) /dev/sd<x>2 -> Swap Partition: 2G
|
||||
(iii) /dev/sd<x>3 -> Root partition: Any of the left space.
|
||||
|
||||
6. Format the disks.
|
||||
|
||||
-> Format the disks using the following commands.
|
||||
-> Taking into conideration that the number of paritions is 3 and same as of the above.
|
||||
|
||||
-> Formating the EFI partition.
|
||||
root@archiso~# mkfs.fat -F32 /dev/sd<x>1
|
||||
|
||||
-> Formating the swap partition.
|
||||
root@archiso~# mkswap /dev/sd<x>2
|
||||
|
||||
-> Formatting the root partition.
|
||||
-> Turning off Journaling.
|
||||
root@archiso~# mkfs.ext4 -o "^has_journal" /dev/sd<x>3
|
||||
|
||||
7. Mounting the partitions.
|
||||
|
||||
-> Mounting swap partition.
|
||||
root@archiso~# swapon /dev/sda2
|
||||
|
||||
-> Mounting the root partition.
|
||||
root@archiso~# mount /dev/sd<x>3 /mnt
|
||||
|
||||
-> Mounting the EFI partition.
|
||||
root@archiso~# mkdir -p /mnt/boot/efi
|
||||
root@archiso~# mount /dev/sd<x>1 /mnt/boot/efi
|
||||
|
||||
8. Installing the required packages.
|
||||
|
||||
-> I am using the vim editor in this tutorial.
|
||||
|
||||
root@archiso~# pacstrap /mnt base linux linux-firmware vim
|
||||
|
||||
9. Generating the format style table.
|
||||
|
||||
root@archiso~# genfstab -U /mnt >> /mnt/etc/fstab
|
||||
|
||||
-> -U option for using the UUIDs.
|
||||
|
||||
10. Change root to the mount directory using the 'arch-chroot /mnt' command.
|
||||
|
||||
11. Set your timezone and sync the harware clock.
|
||||
|
||||
[root@archiso /]# ln -sf /usr/share/zoneinfo/<region>/<city> /etc/localtime
|
||||
|
||||
-> Replace <region> and <city> with your region and city.
|
||||
eg: ln -sf /usr/share/zoneinfo/Asia/Kolkata /etc/localtime
|
||||
|
||||
-> Syncing the harware clock.
|
||||
[root@acrhiso /]# hwclock --systohc
|
||||
|
||||
12. Set your locale.
|
||||
|
||||
[root@archiso /]# vim /etc/locale.gen
|
||||
|
||||
-> The above command will open the locale.gen in vim. Here locate your locale, un-comment it and save the file.
|
||||
-> I will be using the 'en_US.UTF8' locale throught the tutorial.
|
||||
|
||||
13. Generate the locale using the 'locale-gen' command.
|
||||
|
||||
14. Add locale to the locale.conf file.
|
||||
|
||||
[root@archiso /]# echo "LANG=en_US.UTF-8" > /etc/locale.conf
|
||||
|
||||
14. Set the host name.
|
||||
|
||||
[root@archiso /]# echo "ArchUSB" > /etc/hostname
|
||||
|
||||
-> Replace ArchUSB with your hostname.
|
||||
|
||||
15. Edit the hosts file.
|
||||
|
||||
[root@archiso /]# vim /etc/hosts
|
||||
|
||||
-> The above command will open the hosts file in vim. Here, add the following text (replace the hostname)
|
||||
below the comments in the file.
|
||||
|
||||
"""
|
||||
127.0.0.1 localhost
|
||||
::1 localhost
|
||||
127.0.1.1 ArchUSB.localdomain ArchUSB
|
||||
"""
|
||||
|
||||
-> Save the file and quit.
|
||||
|
||||
16. Edit the mkinitcpio.conf file.
|
||||
|
||||
-> As this is a USB flash drive and is going to plugged in more than a single PC, some of the hooks in the
|
||||
mkinitcpio.conf file have to be moved ahead in the order for excepting a normal boot on multiple systems.
|
||||
|
||||
[root@archiso /]# vim /etc/mkinitcpio.conf
|
||||
|
||||
-> In the file that opens, find the HOOKS variable and move block and keyboard ahead of autodetect as shown below.
|
||||
|
||||
-> before
|
||||
HOOKS=(base udev autodetect modconf kms keyboard keymap consolefont block filesystems fsck)
|
||||
|
||||
-> after
|
||||
HOOKS=(base udev block keyboardautodetect modconf kms keymap consolefont filesystems fsck)
|
||||
|
||||
17. Generate Initramfs using the 'mkinitcpio -P linux' command.
|
||||
|
||||
18. Add a user and create a password.
|
||||
|
||||
[root@archiso /]# useradd -mG wheel <user>
|
||||
|
||||
-> Replace <user> with your username.
|
||||
|
||||
[root@archiso /]# passwd <user>
|
||||
|
||||
18. Set a password for root.
|
||||
|
||||
[root@archiso /]# passwd root
|
||||
|
||||
19. Install the required packages.
|
||||
|
||||
[root@archiso /]# pacman -S grub base-devel efibootmgr linux-headers mtools dosfstools reflector networkmanager linux-headers git os-prober nm-connection-editor
|
||||
|
||||
20. Install grub.
|
||||
|
||||
[root@archiso /]# grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=GRUB --removable --recheck
|
||||
|
||||
21. Generate grub configuration file.
|
||||
|
||||
[root@archiso /]# grub-mkconfig -o /boot/grub/grub.cfg
|
||||
|
||||
22. Update sudo privileges.
|
||||
|
||||
[root@archiso /]# editor=vim visudo
|
||||
|
||||
-> The above command will open the visudo file. Here, un-comment the line matching the one below.
|
||||
|
||||
"%wheel ALL=(ALL) ALL"
|
||||
|
||||
-> Save it and exit the file.
|
||||
|
||||
23. Exit to the archiso using the 'exit' command.
|
||||
24. Unmount all the partitions using the 'unmount -a' command.
|
||||
25. Reboot the system using the 'reboot' command.
|
||||
|
||||
26. After rebooting, boot from the USB where arch was installed.
|
||||
27. Login into the used which was added in the installation.
|
||||
|
||||
28. Edit the system journal file.
|
||||
|
||||
-> This is necessary to make the system know that the journal has to be stored in the RAM instead.
|
||||
-> Follow the below command to create and update the journal file.
|
||||
|
||||
# mkdir /etc/systemd/journal.conf.d
|
||||
# vim /etc/systemd/journal.conf.d/usbstick.conf
|
||||
|
||||
-> In the file that opens, save the text below.
|
||||
|
||||
"""
|
||||
[Journal]
|
||||
Storage=volatile
|
||||
MaxRuntimeUse=30M
|
||||
"""
|
||||
|
||||
-> MaxRuntimeUse set to 30M as recommended by the ArchWiki.
|
||||
|
||||
29. So, Arch is now successfully installed on your system.
|
||||
|
||||
Reached a new milestone: "BTW, I use Arch!"
|
||||
351
joplin notion extension/linux/Arch/Installation.md
Normal file
|
|
@ -0,0 +1,351 @@
|
|||
Installation
|
||||
|
||||
https://wiki.archlinux.org/title/installation_guide
|
||||
offline installation : https://medium.com/@elohash/how-to-install-arch-linux-without-internet-no-pacman-9314836949de
|
||||
|
||||
https://docs345.surge.sh/arch_installation/
|
||||
|
||||
|
||||
This video is used for the following steps: https://www.youtube.com/watch?v=DPLnBPM4DhI
|
||||
https://files.catbox.moe/u3tkye.mp4
|
||||
|
||||
- `iwctl`
|
||||
- https://m.youtube.com/watch?v=3czrHtFHteY
|
||||
`device list`
|
||||
`station wlan0 scan` then `station wlan0 get-networks`
|
||||
then connect to internet using
|
||||
`station <device_name> connect <ssid>`
|
||||
Eg: `station wlan0 connect Comcast-50`
|
||||
and `quit`. then ping it by to check if internet is working
|
||||
`ping x.org`.
|
||||
- Update time with `timedatectl`
|
||||
- Partitioning disk
|
||||
- Check partition using `fdisk -l` or `lsblk` or `cfdisk`
|
||||
- Then `fdisk <partition>`
|
||||
eg: `fdisk /dev/sda`
|
||||
- Type these commands in sequence:
|
||||
`p` to print information
|
||||
`o` to create new label
|
||||
`n` to add new partition. So many prompts will come just press enter to select default.
|
||||
|
||||
- Press `t` and Choose lvm by typing `8E` then type `a` to make partition active.
|
||||
- Finalize change type `w` then enter
|
||||
- Then create physical volume using
|
||||
`pvcreate --dataalignment 1m /dev/sda1`
|
||||
- Now create volume group
|
||||
`vgcreate volgroup0 /dev/sda1` . Here `volgroup0` is a group name.
|
||||
- Now create 2 logical volumes ie lv_root and lv_home
|
||||
`lvcreate -L 30GB volgroup0 -n lv_root`
|
||||
and
|
||||
`lvcreate -l 100%FREE volgroup0 -n lv_home`
|
||||
- Load new volume group into memory
|
||||
`modprobe dm_mod`
|
||||
- Scan system for volume groups
|
||||
`vgscan` and activate it
|
||||
`vgchange -ay`
|
||||
- Formatting volumes
|
||||
- Now format these parttions. For root one , format it with ext4 and for swap one format with swap
|
||||
Ext4 formatting
|
||||
`mkfs.ext4 /dev/volgroup0/lv_root`
|
||||
Mounting
|
||||
`mount /dev/volgroup0/lv_root /mnt`
|
||||
|
||||
Now format 2nd logical volume and mount it
|
||||
`mkfs.ext4 /dev/volgroup0/lv_home`
|
||||
Mounting
|
||||
`mkdir /mnt/home`
|
||||
`mount /dev/volgroup0/lv_home /mnt/home`
|
||||
|
||||
If there r swap partitions then
|
||||
Format the Swap Partition (if created): If you created a swap partition, format it as swap:
|
||||
`mkswap /dev/sdX2` # Replace /dev/sdX2 with your swap partition
|
||||
`swapon /dev/sdX2` # Activate the swap partition
|
||||
|
||||
`mkdir /mnt/etc`
|
||||
Saving partition layout by:
|
||||
`genfstab -U -p /mnt >> /mnt/etc/fstab`
|
||||
|
||||
|
||||
- For UEFI
|
||||
Difference here is that we need to create efi partition
|
||||
After typing `fdisk /dev/sda` type these commands:
|
||||
`p` and `g`(for new GPT) , `n` then
|
||||
- Partition number and First sector is default but for last sector we need to change it So type `+500M` as 500mb is enough for efi
|
||||
|
||||
Now type `t` and and partition type is `1` which means efi
|
||||
- Now one more partition for rest
|
||||
So type `n` and just select defaults and set the type with `t` and set to lvm
|
||||
- Partition number would be 2 which is default
|
||||
- Type `30` for lvm
|
||||
- Finally verify it by `p` and type `w` to make changes
|
||||
|
||||
For parttion 1 ie efi , it have to be formatted with fat32
|
||||
`mkfs.fat -F32 /dev/sda1`
|
||||
Here `-F32` represents fat32
|
||||
Now instead of creating and volume and setting other steps for lvm use sda2 instead of sda1 .
|
||||
|
||||
- For UEFI with encryption
|
||||
|
||||
|
||||

|
||||
this should be. 1st to efi,2nd to linux filesystem and 3rd to linux lvm
|
||||
|
||||
Do same for efi and set ext4 for partition 2 but before formatting 4rd we need to encrypt it
|
||||
- Setting encryption
|
||||
`cryptsetup luksFormat /dev/sda3`
|
||||
Now u need to type passphrase. This passphrase should be available else all data will remain encrypted and inaccessible. After typing passphrase it will get locked so type
|
||||
`cryptsetup open --type luks /dev/sda3 lvm`
|
||||
|
||||
Now just create volume , format and mount
|
||||
`pvcreate --dataalignment 1m /dev/mapper/lvm`
|
||||
|
||||
- Installing components
|
||||
- Using pacstrap command
|
||||
`pacstrap -i /mnt base`
|
||||
There mey be a error related to keyring hell so to fix it use
|
||||
https://wiki.archlinux.org/title/Pacman/Package_signing#Resetting_all_the_keys
|
||||
In `/etc/pacman.conf`
|
||||
```text
|
||||
SigLevel = Never
|
||||
#LocalFileSigLevel = Optional
|
||||
#RemoteFileSigLevel = Required
|
||||
```
|
||||
|
||||
- Configure our installation
|
||||
`arch-chroot /mnt` Using in chroot environment. arch-chroot is like a fake-root which change to new directory so that u can make changes af if they r live but all those changes will take place in future.
|
||||
- Inside chroot, install 4 packages ie linux, linux-headers and linux-lts, linux-lts-headers. 2 versions bcz if one dont work then other may work. lts means here 'long term support' hence stable. Use
|
||||
`pacman -S linux linux-headers linux-lts linux-lts-headers linux-firmware`
|
||||
Then few more packages like nano, base-devel(basic development tools), openssh(remote access)
|
||||
To use openssh make sure to enable sshd
|
||||
`systemctl enable sshd`
|
||||
|
||||
Install packages for network working
|
||||
`pacman -S networkmanager wpa_supplicant wireless_tools netctl`
|
||||
|
||||
installing dialog if gui network interface not working
|
||||
`pacman -S dialog`
|
||||
Then finally enable NetworkManager so it will be started when booted
|
||||
`systemctl enable NetworkManager`
|
||||
|
||||
Installing lvm support
|
||||
`pacman -S lvm2`
|
||||
|
||||
To ensure boot process support our configuration, we have to modify a config file
|
||||
`nano /etc/mkinitcpio.conf`
|
||||
now using Ctrl+W find the `HOOKS` which is not commented. Between block and filesystems word,
|
||||
add `lvm2` . if used encryption then add `encrypt lvm2`.
|
||||
|
||||
|
||||
- Resizing partition
|
||||
`lvdisplay` and `vgdisplay`
|
||||
|
||||
Shrink LV
|
||||
If something goes wrong with length of partition then u need to resize it
|
||||
`umount /dev/VG_NAME/lv_home` # Unmount the LV (replace VG_NAME with your volume group)
|
||||
`e2fsck -f /dev/volgroup0/lv_home` # to check file system consistency and check for errors,bad block.
|
||||
`resize2fs /dev/VG_NAME/lv_home NEW_SIZE` # Shrink the filesystem
|
||||
`lvreduce -L NEW_SIZE /dev/VG_NAME/lv_home` # Shrink the logical volume
|
||||
|
||||
Extend LV
|
||||
`lvextend -L +NEW_SIZE /dev/VG_NAME/lv_root` # Extend the logical volume
|
||||
or
|
||||
`lvextend -l +100%FREE /dev/VG_NAME/lv_root`
|
||||
`e2fsck -f /dev/volgroup0/lv_root`
|
||||
`resize2fs /dev/VG_NAME/lv_root` # Resize the filesystem to use the new space
|
||||
|
||||
- Initramfs
|
||||
To take all these setups and option take effect use this
|
||||
`mkinitcpio -p linux`
|
||||
`mkinitcpio -p linux-lts`(As this was also installed)
|
||||
Then set the locale by
|
||||
`nano /etc/locale.gen`
|
||||
Then choose en us and uncomment it
|
||||
`locale-gen`
|
||||
|
||||
Updating password
|
||||
`passwd` then type password to set it
|
||||
|
||||
Creating standard user
|
||||
`useradd -m -g users -G wheel hvm`
|
||||
`-m` means creating home directory for the user, `-g` represents initial login group, `-G` are other supplementary groups. `hvm` is user name.
|
||||
Then set password for this user
|
||||
`passwd hvm` and set password.
|
||||
After this we dont have to use root account always, instead we can use sudo
|
||||
|
||||
Now we need to associate wheel group with sudo
|
||||
`EDITOR=nano visudo`
|
||||
`visudo` is a dedicated command to modify sudo priviledges
|
||||
Scroll down and search for `%wheel ALL=(ALL:ALL) ALL` and uncomment it and save the file.
|
||||
Now user can use sudo to run administrative task.
|
||||
|
||||
- Installing GRUB
|
||||
Its purpose is to boot the OS without bootable media like USB or CD.
|
||||
- For non-UEFI(BIOS)
|
||||
Install this:
|
||||
`pacman -S grub dosfstools os-prober mtools`
|
||||
and finally
|
||||
`grub-install --target=i386-pc --recheck /dev/sda`
|
||||
|
||||
- For UEFI install these
|
||||
`pacman -S grub efibootmgr dosfstools os-prober mtools`
|
||||
|
||||
`mkdir /boot/EFI`
|
||||
`mount /dev/sda1 /boot/EFI`
|
||||
and finally
|
||||
`grub-install --target=x86_64-efi --bootloader-id=grub_uefi --recheck`
|
||||
|
||||
Check if grub exists by this:
|
||||
`ls -l /boot/grub`
|
||||
|
||||
- Others
|
||||
`cp /usr/share/locale/en\@quot/LC_MESSAGES/grub.mo /boot/grub/locale/en.mo`
|
||||
- With encryption
|
||||
`nano /etc.default/grub` then uncomment `GRUB_ENABLE_CRYPTODISK=y`
|
||||
and edit the line
|
||||
#add this GRUB_CMDLINE_LINUX_DEFAULT="cryptodevice=/dev/sda3:volgroup0:allow-discards loglevel=3 quiet"
|
||||
|
||||
- Generate grub config file
|
||||
`grub-mkconfig -o /boot/grub/grub.cfg`
|
||||
Finally
|
||||
`exit` and `umount -a` (to unmount everything)
|
||||
Finally `reboot`
|
||||
|
||||
### Post install tweeks
|
||||
- Creating swap file(not partition)
|
||||
`su`
|
||||
`cd /root`
|
||||
The dd command in Linux is a versatile utility used for copying and converting files, including data from files, devices, partitions, or even raw disk images. The command's name, "dd," stands for "data duplicator."
|
||||
`dd if=/dev/zero of=/swapfile bs=1M count=1024 status=progress`
|
||||
Changing permissions of swapfile
|
||||
`chmod 600 /swapfile`
|
||||
Formatting it to swap
|
||||
`mkswap /swapfile`
|
||||
Backing up copy of fstab file as we going to edit it
|
||||
`cp /etc/fstab /etc/fstab.bak`
|
||||
Editing it
|
||||
`echo '/swapfile none swap sw 0 0' | tee -a /etc/fstab`
|
||||
It will add the line
|
||||
|
||||
`free -m` to check is swap is there
|
||||
`mount -a`(if it runs means no error)
|
||||
|
||||
To activate swap
|
||||
`swapon -a` and check it with `free -m`
|
||||
|
||||
- Setting time zone
|
||||
Listing it
|
||||
`timedatectl list-timezones`
|
||||
Setting it
|
||||
`timedatectl set-timezone <from_list>`
|
||||
Enabling it
|
||||
`systemctl enable systemd-timesyncd`
|
||||
|
||||
Setting host name
|
||||
`hostnamectl set-hostname archhost` here 'archhost' is host name
|
||||
Editing hosts file
|
||||
`nano /etc/hosts`
|
||||
and add
|
||||
```
|
||||
127.0.0.1 localhost
|
||||
127.0.1.1 archhost
|
||||
```
|
||||
and save it
|
||||
To check it
|
||||
`hostnamectl`
|
||||
This image will be the output
|
||||
|
||||
|
||||

|
||||
|
||||
**Installing micro code for CPU**(optional)
|
||||
AMD CPU
|
||||
`pacman -S amd-ucode`
|
||||
or
|
||||
Intel CPU
|
||||
`pacman -S intel-ucode`
|
||||
|
||||
- **GUI**
|
||||
- Installing xorg
|
||||
`pacman -S xorg-server`
|
||||
- Installing video driver
|
||||
For Intel or AMD GPU
|
||||
`pacman -S mesa`
|
||||
For NVIDIA GPU
|
||||
`pacman -S nvidia-lts nvidia`
|
||||
For VBox
|
||||
`pacman -S virtualbox-guest-utils xf86-video-vmware`
|
||||
and enable vbox extension
|
||||
`systemctl enable vboxservice`
|
||||
For QEMU, this might improve performance
|
||||
`sudo pacman -S xf86-video-qxl
|
||||
`
|
||||
And configure it too
|
||||
`sudo mkdir -p /etc/X11/xorg.conf.d`
|
||||
`sudo nano /etc/X11/xorg.conf.d/20-qxl.conf
|
||||
`
|
||||
Type this
|
||||
```
|
||||
Section "Device"
|
||||
Identifier "qxl"
|
||||
Driver "qxl"
|
||||
Option "AccelMethod" "glamor"
|
||||
EndSection
|
||||
|
||||
```
|
||||
and save it
|
||||
|
||||
|
||||
- Installing Desktop Environment
|
||||
- GNOME
|
||||
`pacman -S GNOME`
|
||||
it will store many dependencies as its a package group
|
||||
Some other optional
|
||||
`pacman -S gnome-tweaks` this will give more control over the environment
|
||||
|
||||
Enable display manager
|
||||
`systemctl enable gdm`
|
||||
This will enable login screen
|
||||
Specify the language in Region and Language section else terminal wont open
|
||||
- Plasma
|
||||
`pacman -S plasma-meta kde-applications`
|
||||
Enable display manager
|
||||
`systemctl enable sddm`
|
||||
- Xfce
|
||||
`pacman -S xfce4 xfce4-goodies`
|
||||
Install display manager
|
||||
`pacman -S lightdm lightdm-gtk-greeter`
|
||||
Enabling it
|
||||
`systemctl enable lightdm`
|
||||
- Packages in xfce
|
||||
: There are 15 members in group xfce4:
|
||||
:: Repository extra
|
||||
```
|
||||
1) exo 2) garcon 3) thunar 4) thunar-volman 5) tumbler
|
||||
6) xfce4-appfinder 7) xfce4-panel 8) xfce4-power-manager 9) xfce4-session
|
||||
10) xfce4-settings 11) xfce4-terminal 12) xfconf 13) xfdesktop 14) xfwm4
|
||||
15) xfwm4-themes
|
||||
Enter a selection (default=all):
|
||||
:: There are 36 members in group xfce4-goodies:
|
||||
:: Repository extra
|
||||
|
||||
1) mousepad 2) parole 3) ristretto 4) thunar-archive-plugin
|
||||
5) thunar-media-tags-plugin 6) xfburn 7) xfce4-artwork
|
||||
8) xfce4-battery-plugin 9) xfce4-clipman-plugin 10) xfce4-cpufreq-plugin
|
||||
11) xfce4-cpugraph-plugin 12) xfce4-dict 13) xfce4-diskperf-plugin
|
||||
14) xfce4-eyes-plugin 15) xfce4-fsguard-plugin 16) xfce4-genmon-plugin
|
||||
17) xfce4-mailwatch-plugin 18) xfce4-mount-plugin 19) xfce4-mpc-plugin
|
||||
20) xfce4-netload-plugin 21) xfce4-notes-plugin 22) xfce4-notifyd
|
||||
23) xfce4-pulseaudio-plugin 24) xfce4-screensaver 25) xfce4-screenshooter
|
||||
26) xfce4-sensors-plugin 27) xfce4-smartbookmark-plugin
|
||||
28) xfce4-systemload-plugin 29) xfce4-taskmanager
|
||||
30) xfce4-time-out-plugin 31) xfce4-timer-plugin 32) xfce4-verve-plugin
|
||||
33) xfce4-wavelan-plugin 34) xfce4-weather-plugin
|
||||
35) xfce4-whiskermenu-plugin 36) xfce4-xkb-plugin
|
||||
```
|
||||
|
||||
as
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
35
joplin notion extension/linux/Arch/Issues and VM.md
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
Issues and VM
|
||||
|
||||
- GUI not working and get stuck
|
||||
go to other tty using `Ctrl+alt+F2` or `Ctrl+alt+F3`.... and access the shell and undo changes which caused such issue
|
||||
- Stuck with low resolution
|
||||
With virtio as graphic driver, change resolution is display settings of guest os itself
|
||||
- Screen tearing
|
||||
Try 3 cases
|
||||
1. Enable 3d acceleration in 'video virtio' section which can be found in view and change console to details
|
||||
2. Enable opengl which in 'display splice'
|
||||
3. Do both
|
||||
|
||||
- Enable Clipboard sharing
|
||||
1. Make sure splice protocol is enabled
|
||||
2. Install `splice-vdagent` via pacman.
|
||||
3. Reboot it
|
||||
|
||||
- Enable File sharing
|
||||
https://www.debugpoint.com/share-folder-virt-manager/
|
||||
1. In Details section of current VM go to 'Add Hardware' and add filesystem with source path like `home/user/shared` and target path `shared`. Here shared is random name to be used later for mount. Make sure `vitiofs` is there as driver
|
||||
2. Then restart VM and make any specific directory like `home/user/shared` and make it as mount point by following command
|
||||
`sudo mount -t virtiofs shared /home/hvm/shared`
|
||||
|
||||
- video driver not working
|
||||
it may be possible that we forget to install linux firmware or video driver is missing so we can use `nomodeset` to atleast have access to cli. When in grub navigate to arch linux, dont click enter, type `e` there and at end of line starting with linux add `nomodeset` after word `quiet`.
|
||||
- Wifi Manager not available
|
||||
`sudo pacman -Sy network-manager-applet`
|
||||
- package repo out of date
|
||||
Neither
|
||||
Your database is outdated and has a link to an old version
|
||||
the mirror doesn't cache every old version
|
||||
if you want to do that you can set up your own mirror that just doesn't delete any packages lol
|
||||

|
||||
u can use this
|
||||
https://archive.archlinux.org to download old packages
|
||||
28
joplin notion extension/linux/Arch/connect wifi.md
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
connect wifi
|
||||
|
||||
https://www.makeuseof.com/connect-to-wifi-with-nmcli/
|
||||
https://wiki.archlinux.org/title/Network_configuration/Wireless
|
||||
|
||||
- Check network status by
|
||||
`nmcli dev status`
|
||||
- Also make sure that services NetworkManager,wpa_supplicant is started and enabled
|
||||
`sudo systemctl enable --now NetworkManager`
|
||||
- Check if wifi is enabled or not by
|
||||
`nmcli radio wifi`. if not enabled then type `nmcli radio wifi on` .
|
||||
- Check available wifi networks using
|
||||
`nmcli dev wifi list`
|
||||
- Connecting to specific network
|
||||
To connect with no password
|
||||
`sudo nmcli dev wifi connect network-ssid`
|
||||
Eg: `sudo nmcli dev wifi connect fiber-2`
|
||||
To connect with password
|
||||
`sudo nmcli dev wifi connect network-ssid password <password>`
|
||||
Eg : if password is pass then
|
||||
`sudo nmcli dev wifi connect network-ssid password pass`
|
||||
For interactive password typing ie taking input in order to hide it
|
||||
`sudo nmcli --ask dev wifi connect network-ssid`
|
||||
|
||||
- View saved connections
|
||||
`nmcli con show`
|
||||
- Connect another saved connection
|
||||
`nmcli con up ssid/uuid`
|
||||
60
joplin notion extension/linux/Arch/grub.md
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
grub
|
||||
|
||||
old hp
|
||||
Partition name: archcraft │
|
||||
│ Partition UUID: 29EF9697-4189-48F2-830A-2A4DCC8AEE40 │
|
||||
│ Partition type: Linux filesystem (0FC63DAF-8483-4772-8E79-3
|
||||
|
||||
Partition UUID: 67570847-3D7F-421F-9C04-13BBE306F866 │
|
||||
│ Partition type: Linux swap (0657FD6D-A4AB-43C4-84E5-0933C84B4F4F) │
|
||||
│Filesystem UUID: 0c9b4784-84b0-437a-b50a-8544cc569e18 │
|
||||
└─────────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
Ubuntu
|
||||
Partition UUID: 945D0C81-1B6A-42F7-B517-6FD37E8EA9DA │
|
||||
│ Partition type: Linux filesystem (0FC63DAF-8483-4772-8E79-3D69D8477DE4) │
|
||||
│Filesystem UUID: eee3ebe8-2bcc-43c1-b8db-5e627635417b
|
||||
|
||||
|
||||
Arch
|
||||
Partition UUID: C604A90F-30C0-4C55-933C-FF51320B83EC │
|
||||
│ Partition type: Linux root (x86) (44479540-F297-41B2-9AF7-D131D5F0458A) │
|
||||
│Filesystem UUID: b0425c17-5b5e-49cf-bbbc-f2d959fac780
|
||||
|
||||
|
||||
|
||||
Learning:
|
||||
|
||||
- add distro to grub
|
||||
https://www.youtube.com/watch?v=okYxL7f1VYs
|
||||
make sure that os-prober is enabled in `/etc/default/grub`
|
||||
uncomment following line yo enable it
|
||||
`GRUB_DISABLE_OS_PROBER=false`
|
||||
Now run `sudo os-prober`
|
||||
it will list other distro but not the current one. Make sire that other distros are mounted
|
||||
finally use
|
||||
`sudo grub-mkconfig -o /boot/grub/grub/cfg` to update grub menu
|
||||
|
||||
|
||||
|
||||
- remove systemd-boot
|
||||
`bootctl remove`
|
||||
|
||||
|
||||
- `lsblk -o name,type,uuid`
|
||||
https://www.reddit.com/r/archlinux/comments/tqzodn/other_distros_not_detect_after_fresh_installation/
|
||||
manual way
|
||||
```
|
||||
menuentry "Ubuntu" {
|
||||
# assuming that UUID is 763A-9CB6
|
||||
search --no-floppy --set=root --fs-uuid eee3ebe8-2bcc-43c1-b8db-5e627635417b
|
||||
|
||||
# search by label OTHER_LINUX (make sure that partition label is unambiguous)
|
||||
#search --no-floppy --set=root --label OTHER_LINUX
|
||||
|
||||
linux /boot/vmlinuz root=UUID=eee3ebe8-2bcc-43c1-b8db-5e627635417b
|
||||
#initrd /boot/initrd.img (if the other kernel uses/needs one)
|
||||
initrd /boot/amd-ucode.img /boot/initramfs-linux-lts.img
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
offline installation of arch
|
||||
To bundle packages in an Arch ISO file, modify pacstrap to install packages from the bundled version of the ISO rather than the Arch repositories, and to run a script that is also bundled in the ISO, you'll need to follow several steps. This process involves creating a custom Arch Linux ISO that includes your desired packages and scripts, then modifying the installation scripts to use these bundled resources. Below is an outline of how you can achieve this. Keep in mind, this is a high-level overview and certain steps might require deeper knowledge of Arch Linux, bash scripting, and the inner workings of the Arch ISO.
|
||||
|
||||
### Step 1: Download the Arch ISO
|
||||
|
||||
Download the latest Arch ISO from the official Arch Linux website.
|
||||
|
||||
### Step 2: Extract the ISO
|
||||
|
||||
Mount the ISO to a directory or extract its contents using tools like `7z` or `bsdtar` to a working directory.
|
||||
|
||||
```bash
|
||||
mkdir archiso
|
||||
bsdtar -xpf archlinux.iso -C archiso
|
||||
```
|
||||
|
||||
### Step 3: Customize the AIROOTFS (Arch ISO Root File System)
|
||||
|
||||
This section includes adding your packages and scripts.
|
||||
|
||||
#### Adding Packages:
|
||||
1. Custom packages that are not in the official repositories (or any AUR packages) should be built into `.pkg.tar.zst` files.
|
||||
2. Copy these package files into the `archiso/airootfs/root/` directory (or a subdirectory). This way, they will be available on the live filesystem.
|
||||
|
||||
#### Adding Scripts:
|
||||
1. Write your custom script that performs the desired tasks (e.g., post-installation setup).
|
||||
2. Add this script to the `archiso/airootfs/root/` directory so that you can run it after booting into your custom ISO.
|
||||
|
||||
### Step 4: Modify Pacstrap (Optional)
|
||||
|
||||
Modifying `pacstrap` itself might not be necessary. Instead, consider using a script to manually install the packages using `pacman -U` command from your bundled packages:
|
||||
|
||||
1. Inside your custom script added in the previous step, navigate to where you've stored your packages (e.g., `/root/your_packages/`).
|
||||
2. Install them using `pacman -U /path/to/package.pkg.tar.zst`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Customizing an Arch Linux ISO to include additional packages and modify the `pacstrap` script can be quite involved but entirely feasible. To add packages directly into your ISO and change how `pacstrap` operates to install these packages, you'll need to work with the Arch ISO build system and the `airootfs` (Arch ISO root filesystem) environment. Moreover, to run a custom script bundled in the ISO, you'll need to modify the system's startup process.
|
||||
|
||||
Here are the broad steps you'd follow to achieve your goals:
|
||||
|
||||
### 1. Prepare the Environment
|
||||
|
||||
First, ensure you have all the necessary tools and dependencies. You'll need the `archiso` package, which gives you the tools to create custom live CDs.
|
||||
|
||||
```bash
|
||||
sudo pacman -S archiso
|
||||
```
|
||||
|
||||
### 2. Create Your Working Directory
|
||||
|
||||
Copy the `archiso` profile to create your own customizable profile.
|
||||
|
||||
```bash
|
||||
cp -r /usr/share/archiso/configs/releng/ ~/customiso
|
||||
cd ~/customiso
|
||||
```
|
||||
|
||||
### 3. Bundle Packages
|
||||
|
||||
To add packages directly to the ISO, modify the `packages.x86_64` file located in your custom ISO directory. Just add the names of the packages you wish to include. Note that these packages must be available in the regular Arch repositories or on your custom repository.
|
||||
|
||||
### 4. Modify the Pacstrap Script
|
||||
|
||||
The `pacstrap` script is part of the `arch-install-scripts` package, and it's not directly included in your ISO. `pacstrap` pulls packages from the official repositories during system installation. To change this functionality, you have several options:
|
||||
|
||||
- **Pre-install Packages**: Instead of modifying `pacstrap`, you could pre-install your desired packages into the `airootfs` root file system using the `mkarchiso` command. You can do this by specifying additional packages in the `packages.x86_64` file, as mentioned before, and they'll be installed when you build your ISO.
|
||||
|
||||
- If you insist on modifying `pacstrap` behavior, consider this: When `pacstrap` is run in the Arch ISO environment, it's actually pulling from the live environment (including any modifications you've made). If you want `pacstrap` to pull packages from a specific source, such as packages bundled within the ISO, you would likely need to create a local repository within your ISO and modify the `pacstrap` script (or a custom script called from `airootfs/root/.automated_script.sh`) to prioritize or exclusively use this repository.
|
||||
|
||||
### 5. Include and Run a Custom Script
|
||||
|
||||
To run a custom script from the ISO:
|
||||
|
||||
1. **Place Your Script**: Put your custom script in the `airootfs/root/` directory of your custom ISO project. This ensures it is part of the filesystem that is built into the ISO.
|
||||
|
||||
2. **Autostart Your Script**: Modify the `airootfs/root/customize_airootfs.sh` file to call your script upon boot. This script runs as the last step of the ISO customization process.
|
||||
|
||||
```bash
|
||||
echo "/root/mycustomscript.sh" >> airootfs/root/.zlogin
|
||||
```
|
||||
|
||||
Or, directly invoke your script from `airootfs/root/.automated_script.sh` if you are aiming for an automated installation.
|
||||
|
||||
### 6. Build Your ISO
|
||||
|
||||
Follow the `archiso` instructions to build your ISO. This typically involves running the `mkarchiso` command in your custom ISO directory.
|
||||
|
||||
```bash
|
||||
sudo mkarchiso -v ~/customiso
|
||||
```
|
||||
|
||||
### Final Notes
|
||||
|
||||
- **Handling Repositories**: Bundling packages inside the ISO for `pacstrap` to use is unconventional. Instead, consider either pre-installing packages or setting up a local repository within your ISO and having `pacstrap` use it. Handling dependencies correctly is crucial here.
|
||||
- **Testing**: Always test your custom ISO in a safe environment (like a VM) before using it in a production context.
|
||||
- **Custom `pacstrap` Logic**: If you modify how `pacstrap` operates (e.g., to use a local repository), you might need to also ensure that the mirrorlist or `pacman` configuration used respects this customization.
|
||||
- **Resolution**: Depending on your precise use case (specific packages or scripts execution), there might be simpler or more straightforward approaches to achieving your goals, such as scripting post-install actions instead of deeply customizing the install process.
|
||||
|
||||
Customizing Arch Linux and automating installations can be a powerful way to create a tailored environment, but it requires careful planning and testing to ensure system stability and security.
|
||||
|
||||
|
||||
|
||||
```bash
|
||||
# 1. Prepare your packages
|
||||
# Download packages or use pacman to download them along with dependencies
|
||||
|
||||
# 2. Create a custom repository
|
||||
# Create a directory to store your packages
|
||||
mkdir custom_repo
|
||||
# Add packages to your custom repository
|
||||
repo-add custom_repo/custom.db.tar.gz <package1>.pkg.tar.zst <package2>.pkg.tar.zst ...
|
||||
|
||||
# 3. Modify the Arch Linux ISO
|
||||
# Extract the Arch Linux ISO
|
||||
mkdir arch_iso
|
||||
bsdtar -xf archlinux.iso -C arch_iso
|
||||
# Add your custom repository to the Arch Linux ISO
|
||||
cp -r custom_repo arch_iso
|
||||
|
||||
# 4. Modify pacstrap
|
||||
# Edit the pacstrap script in the arch_iso directory to use your custom repository
|
||||
|
||||
# 5. Create a script
|
||||
# Create your script and make it executable
|
||||
chmod +x your_script.sh
|
||||
|
||||
# 6. Bundle everything into a new ISO
|
||||
# Create a new ISO with your modifications
|
||||
xorriso -as mkisofs -iso-level 3 -full-iso9660-filenames -volid "Custom Arch Linux" -o custom_archlinux.iso arch_iso
|
||||
|
||||
# Clean up temporary files if necessary
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,266 @@
|
|||
sway compositor installation
|
||||
https://wiki.garudalinux.org/en/sway-cheatsheet
|
||||
|
||||
Make sure to have these list of tools that are alternative of x11 ones
|
||||
https://soyuka.me/make-screen-sharing-wayland-sway-work/
|
||||
|
||||
todo
|
||||
- network stats on waybar
|
||||
- sleep/power button
|
||||
- wifi manager
|
||||
|
||||
|
||||
- Installing packages
|
||||
sudo pacman -S sway swaybg foot polkit
|
||||
- Type `sway` after opening it with `Super + Enter`
|
||||
- Fixing resolution
|
||||
First copy the config of sway to config of user directroy
|
||||
```bash
|
||||
mkdir -p ~/.config/sway
|
||||
cp /etc/sway/config ~/.config/sway/
|
||||
$EDITOR ~/.config/sway/config
|
||||
```
|
||||
In order to get device name and other availableresolutions and info type
|
||||
`swaymsg -t get_outputs`
|
||||
Then enabling it with
|
||||
`output HDMI-A-1 mode 1920x1080@60Hz`
|
||||
|
||||
|
||||
### more shotcuts
|
||||
for tabbed mode : mod+D
|
||||
launcher : mod + d
|
||||
to escape tabbed mode : mod + e
|
||||
for fullscreen : mod+f
|
||||
closing focused wndow : mod+shift+q
|
||||
|
||||
to make current window appear on top of others : mod+shift+space
|
||||
and then switch between floating and tiling window : mod + space
|
||||
to change size of floating window : mod + drag with right click (resize mode need to be enabled with win + r to move or resize)
|
||||
- config files
|
||||
main config file is in `/etc/sway` which can be copied to `~/.config` for customization
|
||||
and to load this changed config
|
||||
`swaymsg reload`
|
||||
- to kill kde session use
|
||||
`qdbus org.kde.ksmserver /KSMServer logout 0 0 0`
|
||||
`loginctl terminate-session`
|
||||
`qdbus org.kde.KWin /Session org.kde.KWin.Session.quit `
|
||||
- about audio
|
||||
`pavucontrol` is important for audio output and configuration
|
||||
```sh
|
||||
systemctl --user status pipewire
|
||||
systemctl --user status pipewire-pulse
|
||||
# Sometimes, you may also need:
|
||||
systemctl --user status wireplumber
|
||||
```
|
||||
These are necessary for audio
|
||||
for inspecting
|
||||
```sh
|
||||
pactl list short sinks
|
||||
pactl list short sources
|
||||
```
|
||||
- configuting volume
|
||||
```txt
|
||||
# in config file
|
||||
# Increase volume
|
||||
bindsym XF86AudioRaiseVolume exec pactl set-sink-volume @DEFAULT_SINK@ +5%
|
||||
|
||||
# Decrease volume
|
||||
bindsym XF86AudioLowerVolume exec pactl set-sink-volume @DEFAULT_SINK@ -5%
|
||||
|
||||
# Mute/unmute volume
|
||||
bindsym XF86AudioMute exec pactl set-sink-mute @DEFAULT_SINK@ toggle
|
||||
```
|
||||
if using alsa then
|
||||
```txt
|
||||
# Increase volume
|
||||
bindsym XF86AudioRaiseVolume exec amixer set Master 5%+
|
||||
|
||||
# Decrease volume
|
||||
bindsym XF86AudioLowerVolume exec amixer set Master 5%-
|
||||
|
||||
# Mute/unmute volume
|
||||
bindsym XF86AudioMute exec amixer set Master toggle
|
||||
```
|
||||
- waybar
|
||||
it a tray at top which display stats like ram used, volume, brightness and all
|
||||
download it with `yay -S waybar` and start waybar in terminal
|
||||
Also install `ttf-font-awesome` for icons
|
||||
- brighness(2 ways)
|
||||
- install `light` then
|
||||
```yaml
|
||||
# Increase brightness
|
||||
bindsym XF86MonBrightnessUp exec light -A 10
|
||||
|
||||
# Decrease brightness
|
||||
bindsym XF86MonBrightnessDown exec light -U 10
|
||||
```
|
||||
or
|
||||
- install `brightnessctl` then
|
||||
```yaml
|
||||
# Increase brightness
|
||||
bindsym XF86MonBrightnessUp exec brightnessctl set +10%
|
||||
|
||||
# Decrease brightness
|
||||
bindsym XF86MonBrightnessDown exec brightnessctl set 10%-
|
||||
```
|
||||
|
||||
- Touchpad configurations
|
||||
- Make sure `libinput` is installed
|
||||
- list devices too see device name and find device name of touchpad
|
||||
`libinput list-devices` eg : `1267:12448:ELAN0708:00_04F3:30A0_Touchpad`
|
||||
if identifier property isnt there then use
|
||||
`swaymsg -rt get_inputs`
|
||||
- type this in config
|
||||
```yaml
|
||||
# input "your-device-name"
|
||||
input "1267:12448:ELAN0708:00_04F3:30A0_Touchpad" {
|
||||
# Enable natural (reverse) scrolling
|
||||
natural_scroll enabled
|
||||
|
||||
# Enable tap to click
|
||||
tap enabled
|
||||
}
|
||||
```
|
||||
Instead of `input <DEVICE_IDENTIFIER>` this can can be used to `input type:touchpad`
|
||||
|
||||
|
||||
**Clipboard manager**
|
||||
- make sure wofi is installed and so is wl-clipboard is installed
|
||||
- Create this script
|
||||
```bash
|
||||
#!/bin/bash
|
||||
HISTFILE=~/.clipboard_history
|
||||
|
||||
# Check and create history file if it doesn't exist
|
||||
if [ ! -f $HISTFILE ]; then
|
||||
touch $HISTFILE
|
||||
fi
|
||||
|
||||
# Append new clipboard items to the history
|
||||
wl-paste -n | tee -a $HISTFILE
|
||||
|
||||
# Display history using wofi and copy the selection back
|
||||
selection=$(sort -u $HISTFILE | wofi --show=dmenu)
|
||||
[[ -n "$selection" ]] && echo -n "$selection" | wl-copy
|
||||
```
|
||||
- Bind this with key mod+d
|
||||
`chmod +x ~/scripts/clipboard_history.sh`
|
||||
- Alternatively use copyq
|
||||
|
||||
|
||||
Screenshot
|
||||
- Make sure grimshot and swappy is installed. This command is used to take screenshot
|
||||
`grimshot save area - | swappy -f -`
|
||||
or
|
||||
`grim -g "$(slurp)" - | swappy -f -`
|
||||
- Then add this in config
|
||||
`bindsym $mod+p exec grimshot save area - | swappy -f -`
|
||||
|
||||
|
||||
Network stats
|
||||
- we need to setup a toolkit it involvfes making changes into config so copy its default config from `/etc/xdg/wayland` to `~/.config/wayland`
|
||||
- In `config.jsonc`, make sure to have following in network module
|
||||
```json
|
||||
"network": {
|
||||
// "interface": "wlp2*", // (Optional) To force the use of this interface
|
||||
"format-wifi": "{essid} ({signalStrength}%) ",
|
||||
"format-ethernet": "{ipaddr}/{cidr} ",
|
||||
"tooltip-format": "{ifname} via {gwaddr} ",
|
||||
"format-linked": "{ifname} (No IP) ",
|
||||
"format-disconnected": "Disconnected ⚠",
|
||||
"format-alt": "{ifname}: {ipaddr}/{cidr}",
|
||||
//"format-alt": "{icon} {ifname}: {ipaddr}/{cidr}", // overridden by on-click below (click also toggles format/format-alt)
|
||||
"tooltip-format": "{ifname}\t{ipaddr}/{cidr}\ngateway\t{gwaddr}",
|
||||
"tooltip-format": "{ifname}\t{ipaddr}/{cidr}\ngateway\t{gwaddr}\n\t{essid}\n{icon} ⇣{bandwidthDownBytes} ⇡{bandwidthUpBytes}",
|
||||
"interval" : 2
|
||||
|
||||
},
|
||||
```
|
||||
- then restart waybar
|
||||
|
||||
|
||||
Automatic sleep
|
||||
- main command for sleep is `systemctl suspend`
|
||||
https://askubuntu.com/questions/885936/how-to-properly-suspend-via-command
|
||||
- command for automatic sleep after interval of time
|
||||
`swayidle -w timeout 10 'systemctl suspend'` this will start a daemon
|
||||
means if left idle for 10s system will sleep
|
||||
|
||||
|
||||
obs studio (screen recording)
|
||||
https://www.reddit.com/r/swaywm/comments/w6gca6/comment/ihh86vj/
|
||||
- install `v4l2loopback` and restart your system
|
||||
- wf-recorder can also do screen recording
|
||||
for specific section of screen use this?
|
||||
`wf-recorder -a -g "$(slurp)" -f filename.mp4`
|
||||
`-a` : audio flag
|
||||
also use this to bind with any command for recording
|
||||
`bindsym $mod+o exec wf-recorder -g "$(slurp)" -f ~/Downloads/wfRecorder/$(date +%Y-%m-%d_%H:%M:%S).mp4`
|
||||
and to stop this use
|
||||
`bindsym $mod+ctrl+o exec pkill -SIGINT wf-recorder`
|
||||
or for not including mic and computer audio use this
|
||||
`wf-recorder -g "$(slurp)" --audio=alsa_output.pci-0000_04_00.6.analog-stereo.monitor -f ~/Downloads/wfRecorder/$(date +%Y-%m-%d_%H:%M:%S).mp4`
|
||||
audio sources can be listed by
|
||||
`pactl list short sources`
|
||||
|
||||
- some portals like `xdg-desktop-portal-gtk` and `xdg-desktop-portal-wlr` is recommended to be installed
|
||||
- with obs-studio in order to record potion of screen use alt too when resizing.
|
||||
|
||||
|
||||
wifi applet
|
||||
- install network-manager-applet for arch and use command `nm-applet` to start it in waybar
|
||||
|
||||
|
||||
bluetooth setup
|
||||
- first make sure to enable bluetooth service with `systemctl enable --now bluetooth.service`
|
||||
- Then install blueman which is a gui took which needs to be open through launcher
|
||||
|
||||
|
||||
**Complex keybinding support**
|
||||
In Sway, you can define complex keybindings using the bindsym directive to combine multiple key presses, but creating a "chained" key sequence directly (like keya+keyb followed by keyc) requires a workaround because sway does not natively support multi-key sequences that wait for a subsequent keypress.
|
||||
|
||||
However, you can achieve similar functionality using the bindsym directives along with exec commands that track the state of a key press. Here's a basic approach:
|
||||
|
||||
Define a variable to keep track of your sequence. You can use swaymsg to set environment variables (though this gets tricky and might require additional scripting if you want to create a more complex state machine).
|
||||
|
||||
Use combinations of bindsym. Here’s an example of how you could set up your keybindings in Sway config:
|
||||
```
|
||||
# Reset sequence variable
|
||||
set $sequence ""
|
||||
|
||||
# First key combination
|
||||
bindsym --release $mod+a exec swaymsg set-option persistent_layout "set $sequence a"
|
||||
bindsym --release $mod+b exec swaymsg set-option persistent_layout "set $sequence $sequence b"
|
||||
bindsym --release $mod+c exec swaymsg set-option persistent_layout "set $sequence $sequence c"
|
||||
|
||||
# Action on sequence completion
|
||||
bindsym --released $mod+c exec sh -c 'if [ "$$sequence" = "ab" ]; then <your-action>; fi; set $sequence ""'
|
||||
```
|
||||
This is a simplified illustration; you would need to adapt it to your environment and ensure that you have the proper way to reset the variable after executing your desired action.
|
||||
|
||||
Use a separate script for multi-key functionality (if necessary): Sometimes, handling this with a more robust solution such as a script might be easier. You could use a shell script to read key input and execute an action once a specific sequence is detected.
|
||||
```
|
||||
#!/bin/bash
|
||||
|
||||
# Sample script that waits for a sequence
|
||||
case $1 in
|
||||
"ab")
|
||||
# Run your command here for keya + keyb
|
||||
echo "Action triggered for a + b"
|
||||
;;
|
||||
"c")
|
||||
if [ "$PREV_KEYS" == "ab" ]; then
|
||||
# Run your command for a + b + c
|
||||
echo "Action triggered for a + b + c"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
```
|
||||
Make sure to include this script in your keybinding:
|
||||
|
||||
`bindsym --release $mod+a exec /path/to/your/script.sh "ab"`
|
||||
`bindsym --release $mod+c exec /path/to/your/script.sh "c"`
|
||||
|
||||
Make sure to modify these samples to fit your specific needs. Managing sequences of keys can be complex, so a thorough understanding of how Sway handles input and executing external commands will help you create the solution that works best for you.
|
||||
|
||||
For the best practices and limitations, be sure to check the Sway documentation and community resources as well.
|
||||
27
joplin notion extension/linux/Arch/waydroid.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
waydroid
|
||||
https://github.com/n1lby73/waydroid-installer
|
||||
https://wiki.archlinux.org/title/Waydroid
|
||||
|
||||
- Installation
|
||||
`yay -S waydroid` (AUR package)
|
||||
- Prerequisite
|
||||
As arch linux default kernel arent supported by waydroid so install another one ie `linux-zen` and its headers
|
||||
`yay -Ss linux-zen linux-zen-headers`
|
||||
Now create initrd by (in arch it is mkinitcpio)
|
||||
`mkinitcpio -p linux-zen`
|
||||
Then finally include it in grub file by
|
||||
`grub-mkconfig -o /boot/grub/grub.cfg` and `reboot`
|
||||
and in `Advanced options for arch linux` select `linux-zen` kernel
|
||||
- Initialization
|
||||
Run `sudo waydroid init`
|
||||
It will check in the directory `/usr/images/waydroid-extra/images` if image and vendors are installed or not. If not installed then it will install them of lineageOS in the directory `var/lib/waydroid/images`
|
||||
Make sure that `waydroid-container.service` is started
|
||||
`sudo systemctl enable --now waydroid-container`
|
||||
- Usage
|
||||
Starting waydroid session
|
||||
`waydroid session start`
|
||||
Then in another terminal type
|
||||
`waydroid show-full-ui`
|
||||
|
||||
|
||||
|
||||
58
joplin notion extension/linux/Archiving.md
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
Archiving
|
||||
|
||||
- zip and unzip
|
||||
- Add files/directories to a specific archive:
|
||||
`zip -r path/to/compressed.zip path/to/file_or_directory1 path/to/file_or_directory2 ...`
|
||||
- Archive files/directories with a specific compression level (`0` - the lowest, `9` - the highest):
|
||||
`zip -r -0..9 path/to/compressed.zip path/to/file_or_directory1 path/to/file_or_directory2 ...`
|
||||
|
||||
- Create an encrypted archive with a specific password:
|
||||
`zip -r --encrypt path/to/compressed.zip path/to/file_or_directory1 path/to/file_or_directory2 ...`
|
||||
- Archive files/directories to a multi-part [s]plit Zip archive (e.g. 3 GB parts):
|
||||
`zip -r -s 3g path/to/compressed.zip path/to/file_or_directory1 path/to/file_or_directory2 ...`
|
||||
|
||||
- Print a specific archive contents:
|
||||
`zip -sf path/to/compressed.zip`
|
||||
- Excluding directories or files
|
||||
`zip -r myarchive.zip target -x "target/exclude1/*" "target/exclude2/*"`
|
||||
Exclude all directories within target of particular name(can be nested deep too)
|
||||
`zip -r archive_name.zip /path/to/source -x "*/exclude_dir/*"`
|
||||
- Include hidden directories in zip file
|
||||
`find . -mindepth 1 -print | zip archive_name.zip -@`
|
||||
- `find .` starts the search in the current directory.
|
||||
- `mindepth 1` ensures the search does not include the current directory itself (.) in the results.
|
||||
- `print` outputs the found items.
|
||||
|
||||
|
||||
|
||||
- Extract all files/directories from specific archives into the current directory:
|
||||
`unzip path/to/archive1.zip path/to/archive2.zip ...`
|
||||
- Extract files/directories from archives to a specific path:
|
||||
`unzip path/to/archive1.zip path/to/archive2.zip ... -d path/to/output`
|
||||
|
||||
|
||||
- 7zip
|
||||
- [a]dd a file or directory to a new or existing archive:
|
||||
`7z a path/to/archive.7z path/to/file_or_directory`
|
||||
- Encrypt an existing archive (including filenames):
|
||||
`7z a path/to/encrypted.7z -ppassword -mhe=on path/to/archive.7z`
|
||||
|
||||
- E[x]tract an archive preserving the original directory structure:
|
||||
`7z x path/to/archive.7z`
|
||||
|
||||
- E[x]tract an archive to a specific directory:
|
||||
`7z x path/to/archive.7z -opath/to/output`
|
||||
|
||||
- E[x]tract an archive to `stdout`:
|
||||
`7z x path/to/archive.7z -so`
|
||||
|
||||
- [a]rchive using a specific archive type:
|
||||
`7z a -t7z|bzip2|gzip|lzip|tar|zip path/to/archive path/to/file_or_directory`
|
||||
|
||||
- [l]ist the contents of an archive:
|
||||
`7z l path/to/archive.7z`
|
||||
|
||||
- Set the level of compression (higher means more compression, but slower):
|
||||
`7z a path/to/archive.7z -mx=0|1|3|5|7|9 path/to/file_or_directory`
|
||||
|
||||
|
||||
342
joplin notion extension/linux/Bash Basics.md
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
Bash Basics
|
||||
https://devhints.io/bash
|
||||
|
||||
**Note**
|
||||
- for executing commands if uses single quotes then it will pass literal text , double quotes allows commands and variables to be execured
|
||||
|
||||
|
||||
- for loop
|
||||
```bash
|
||||
for arg in "$@"; do
|
||||
echo "$arg"
|
||||
done
|
||||
|
||||
for (( i=0;i<$filesCount;i++)); do
|
||||
singleFile="${filesArray[$i]}"
|
||||
#here I replace ALL the spaces in the file's name, by underscores.
|
||||
trimmed=${singleFile// /\_}
|
||||
mv "${singleFile}" "${trimmed}"
|
||||
echo "renamed ${singleFile} as ${trimmed} !"
|
||||
done
|
||||
```
|
||||
- if elif else
|
||||
set of if else statements are terminated with fi
|
||||
```bash
|
||||
# String
|
||||
if [[ -z "$string" ]]; then
|
||||
echo "String is empty"
|
||||
elif [[ -n "$string" ]]; then
|
||||
echo "String is not empty"
|
||||
else
|
||||
echo "This never happens"
|
||||
fi
|
||||
|
||||
```
|
||||
- Logical operators
|
||||
```bash
|
||||
# Logical AND and OR
|
||||
if [[ $varA == 1 && ($varB == "t1" || $varC == "t2") ]]; then
|
||||
|
||||
# NOT
|
||||
if ! [[ $var == 2 || $var == 30 || $var == 50 ]] ; then
|
||||
do something
|
||||
fi
|
||||
if [[ ! ($var == 2 || $var == 30 || $var == 50) ]] ; then
|
||||
do something
|
||||
fi
|
||||
|
||||
|
||||
```
|
||||
- Functions
|
||||
```bash
|
||||
myfunc() {
|
||||
echo "hello $1"
|
||||
}
|
||||
|
||||
# Same as above (alternate syntax)
|
||||
function myfunc {
|
||||
echo "hello $1"
|
||||
}
|
||||
|
||||
myfunc "John"
|
||||
|
||||
|
||||
# Returning values
|
||||
myfunc() {
|
||||
local myresult='some value'
|
||||
echo "$myresult"
|
||||
}
|
||||
|
||||
result=$(myfunc)
|
||||
|
||||
|
||||
|
||||
```
|
||||
- Geting filename and extemsion
|
||||
```bash
|
||||
# First, get file name without the path:
|
||||
|
||||
filename=$(basename -- "$fullfile")
|
||||
# or
|
||||
filename="${FILEPATH##*/}"
|
||||
extension_only="${filename##*.}"
|
||||
filename_with_noext="${filename%.*}"
|
||||
|
||||
```
|
||||
- array
|
||||
```bash
|
||||
# Declaring an array
|
||||
arr=()
|
||||
arr1=("hey" "there" "how")
|
||||
arr2=("er" "yu")
|
||||
declare -a arr3=()
|
||||
|
||||
# Declare associative array to be able to have keys rather than index
|
||||
declare -A asscoArr
|
||||
|
||||
# array elements is "${arr1[@]}"
|
||||
for ele in "${arr1[@]}";do
|
||||
echo $ele
|
||||
done
|
||||
|
||||
# Output
|
||||
hey
|
||||
there
|
||||
how
|
||||
|
||||
# array index/keys is "${!arr1[@]}"
|
||||
for i in "${!arr1[@]}";do
|
||||
echo $i
|
||||
done
|
||||
|
||||
# Accessing elements through index
|
||||
"${arr1[2]}"
|
||||
|
||||
# getting length of array
|
||||
${#arr1[@]}
|
||||
|
||||
```
|
||||
- shift
|
||||
To shift arguments to left so that first argument is lost
|
||||
- C like switch case in bash
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Loop through all the arguments
|
||||
for arg in "$@"; do
|
||||
case $arg in
|
||||
-a|--optionA)
|
||||
echo "Option A detected!"
|
||||
# handle option A
|
||||
;;
|
||||
-b|--optionB)
|
||||
echo "Option B detected!"
|
||||
# handle option B
|
||||
;;
|
||||
*)
|
||||
# Handle positional arguments or invalid flags
|
||||
;;
|
||||
esac
|
||||
done
|
||||
```
|
||||
- pasing variable arguments
|
||||
```bash
|
||||
# Define your arguments in an array
|
||||
passargs=(-x '*/node_modules/*')
|
||||
|
||||
# Use the array with the command
|
||||
zip -r archive.zip . "${passargs[@]}"
|
||||
|
||||
|
||||
# following method wont work
|
||||
|
||||
passargs="'-x */node_modules/*'"
|
||||
zip -r $ARCHIVE_NAME $FILES_TO_ARCHIVE $passargs
|
||||
```
|
||||
- convert string which r separted by spaces to array
|
||||
using declare will resolve some bugs related to delimiters
|
||||
```bash
|
||||
# arrow looks like following
|
||||
arr1=('hey' 'there')
|
||||
# if
|
||||
str="hey there"
|
||||
declare -a arr=($str)
|
||||
# now
|
||||
# arr is ('hey' 'there')
|
||||
```
|
||||
- extract parent directory
|
||||
```bash
|
||||
// Output : /home/username
|
||||
echo "$PWD"
|
||||
|
||||
// Output : /home
|
||||
echo "${dirname $PWD}"
|
||||
|
||||
|
||||
```
|
||||
### Examples
|
||||
|
||||
- Find non common elements from 2 array
|
||||
```bash
|
||||
distinctive_files(){
|
||||
|
||||
# dir1=$1
|
||||
# dir2=$2
|
||||
|
||||
# arr1=( $( ls $dir1 ) )
|
||||
# arr2=( $( ls $dir2 ) )
|
||||
|
||||
declare -a arr1=("er" "rt")
|
||||
declare -a arr2=("er" "rt" "ty")
|
||||
|
||||
# echo "arr1: ${arr1[@]}"
|
||||
# echo "arr2: ${arr2[@]}"
|
||||
|
||||
declare -A all_Elements
|
||||
common_Files=()
|
||||
distinct_Files=()
|
||||
|
||||
for elem in "${arr1[@]}";do
|
||||
# echo "elem arr1: $elem"
|
||||
((all_Elements[$elem]++))
|
||||
# echo "arr1 all_Elements: ${all_Elements[$elem]}"
|
||||
done
|
||||
|
||||
for elem in "${arr2[@]}";do
|
||||
# echo "elem arr2: $elem"
|
||||
((all_Elements[$elem]++))
|
||||
# echo "arr2 all_Elements: ${all_Elements[$elem]}"
|
||||
done
|
||||
|
||||
# echo "Non common elements:"
|
||||
for key in "${!all_Elements[@]}" ; do
|
||||
if [ ${all_Elements[$key]} -eq 1 ]; then
|
||||
|
||||
distinct_Files+=($key)
|
||||
fi
|
||||
# echo "key: $key"
|
||||
done
|
||||
|
||||
echo "${distinct_Files[@]}"
|
||||
|
||||
# Calling function
|
||||
disti=$(distinctive_files)
|
||||
|
||||
```
|
||||
- Pass 2 arrays as arguments in bash
|
||||
```bash
|
||||
# by passing number of elements of each array
|
||||
myFunc(){
|
||||
local n1=$1
|
||||
local n2=$2
|
||||
shift 2
|
||||
local arr=("$@")
|
||||
arr1=()
|
||||
arr2=()
|
||||
i=0
|
||||
for ele in "${arr[@]}"; do
|
||||
echo "ele: $ele"
|
||||
if [[ i -ge $n1 ]]; then
|
||||
arr2+=($ele)
|
||||
else
|
||||
arr1+=($ele)
|
||||
fi
|
||||
((i++))
|
||||
done
|
||||
|
||||
echo "arr1 ${arr1[@]}"
|
||||
echo "arr2 ${arr2[@]}"
|
||||
|
||||
|
||||
}
|
||||
|
||||
declare -a arr1=("er" "rt")
|
||||
declare -a arr2=("er" "rt" "ty")
|
||||
|
||||
(added_zipped_files ${#arr1[@]} ${#arr2[@]} ${arr1[@]} ${arr2[@]})
|
||||
|
||||
|
||||
|
||||
# by passing reference(from bash 4.3 released in year 2016)
|
||||
demo_multiple_arrays() {
|
||||
local -n _array_one=$1
|
||||
local -n _array_two=$2
|
||||
printf '1: %q\n' "${_array_one[@]}"
|
||||
printf '2: %q\n' "${_array_two[@]}"
|
||||
}
|
||||
|
||||
array_one=( "one argument" "another argument" )
|
||||
array_two=( "array two part one" "array two part two" )
|
||||
|
||||
demo_multiple_arrays array_one array_two
|
||||
|
||||
```
|
||||
- Append certain character
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Check if a file name is provided as an argument
|
||||
if [ $# -ne 1 ]; then
|
||||
echo "Usage: $0 <filename>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if the file exists
|
||||
if [ ! -f "$1" ]; then
|
||||
echo "File '$1' not found."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Append semicolon to each line in the file
|
||||
while IFS= read -r line; do
|
||||
echo "$line;"
|
||||
done < "$1" > "$1.tmp"
|
||||
|
||||
# Replace the original file with the modified one
|
||||
mv "$1.tmp" "$1"
|
||||
|
||||
echo "Semicolons appended to each line in '$1'."
|
||||
|
||||
```
|
||||
- to display ram of top processes based on ram
|
||||
```sh
|
||||
#!/bin/zsh
|
||||
|
||||
echo "Command PSS (MB)"
|
||||
echo "================================================="
|
||||
|
||||
smem -c "command pss" |
|
||||
awk '{
|
||||
cmd=$1; pss=$2; uss=$3; rss=$4;
|
||||
pssTotal[cmd]+=pss; ussTotal[cmd]+=uss; rssTotal[cmd]+=rss;
|
||||
} END {
|
||||
for (cmd in pssTotal) {
|
||||
# Convert from KB to MB
|
||||
pssMB = pssTotal[cmd] / 1024;
|
||||
printf "%-35s %10.2f MB\n", cmd, pssMB;
|
||||
}
|
||||
}' | sort -k 2 -nr | head -n 10
|
||||
```
|
||||
- random string generation
|
||||
random 16 character alphanumeric string
|
||||
`tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 16; echo ''`
|
||||
pure bash
|
||||
```sh
|
||||
# Define allowed character set
|
||||
chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
||||
length=16
|
||||
result=''
|
||||
|
||||
for ((i=0; i<length; i++)); do
|
||||
result+="${chars:RANDOM%${#chars}:1}"
|
||||
done
|
||||
|
||||
echo "$result"
|
||||
|
||||
```
|
||||
|
||||
|
||||
for have single quotes in literal in bash
|
||||
```bash
|
||||
ffmpeg -i 'The Witcher 3 In the Eternal Fire'\''s Shadow p1.mp4' -o ...
|
||||
```
|
||||
416
joplin notion extension/linux/Basics.md
Normal file
|
|
@ -0,0 +1,416 @@
|
|||
Basics
|
||||
https://linuxcommandlibrary.com/
|
||||
|
||||
- https://www.howtogeek.com/269509/how-to-run-two-or-more-terminal-commands-at-once-in-linux/
|
||||
|
||||
Option One: The Semicolon (;) Operator
|
||||
The semicolon (;) operator allows you to execute multiple commands in succession, regardless of whether each previous command succeeds. For example, open a Terminal window (Ctrl+Alt+T in Ubuntu and Linux Mint). Then, type the following three commands on one line, separated by semicolons, and press Enter. This will give you a listing of the current directory
|
||||
|
||||
Option Two: The Logical AND Operator (&&)
|
||||
If you want the second command to only run if the first command is successful, separate the commands with the logical AND operator, which is two ampersands ( && ). For example, we want to make a directory called MyFolder and then change to that directory--provided it was successfully created. So, we type the following on the command line and press Enter.
|
||||
|
||||
Option Three: The Logical OR Operator (||)
|
||||
Sometimes you might want to execute a second command only if the first command does not succeed. To do this, we use the logical OR operator, or two vertical bars ( || ). For example, we want to check to see if the MyFolder directory exists ( \[ -d ~/MyFolder \] ) and create it if it doesn't ( mkdir ~/MyFolder ). So, we type the following command at the prompt and press Enter.
|
||||
|
||||
|
||||
- bash cheatsheet
|
||||
```bash
|
||||
A; B # Run A and then B, regardless of success of A
|
||||
A && B # Run B if and only if A succeeded
|
||||
A || B # Run B if and only if A failed
|
||||
A & # Run A in background.
|
||||
A & B & : # Run A in background, then run B in background (regardless of success) and return control to the shell
|
||||
```
|
||||
|
||||
- locating commands or bin files
|
||||
`which -a gdb`
|
||||
|
||||
```
|
||||
which: no gdb in (/home/hpm/.local/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl:/var/lib/snapd/snap/bin)
|
||||
|
||||
```
|
||||
|
||||
rt
|
||||
`locate -eb '\gdb'`
|
||||
|
||||
ed
|
||||
|
||||
```bash
|
||||
/usr/share/gdb
|
||||
/usr/share/bash-completion/completions/gdb
|
||||
/usr/share/glib-2.0/gdb
|
||||
/usr/share/gstreamer-1.0/gdb
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
- sed commands usage
|
||||
https://www.tecmint.com/linux-sed-command-tips-tricks/
|
||||
https://www.geeksforgeeks.org/sed-command-in-linux-unix-with-examples/
|
||||
|
||||
|
||||
[Sed Command in Linux_Unix with examples - GeeksforGeeks.pdf](../../_resources/Sed%20Command%20in%20Linux_Unix%20with%20examples%20-%20Geeksfor.pdf)
|
||||
|
||||
|
||||
|
||||
- List files with full path with ls
|
||||
`ls -lrt -d -1 "$PWD"/{*,.*}`
|
||||
or if u want regular expression then
|
||||
`find /path/to/start/directory -type f | awk -F/ '{print "<a href=\""$0"\">"$NF"</a>"}'`
|
||||
here path to directory is path where those files are stored
|
||||
`type -f` means to list only files
|
||||
`find /path/to/start/directory -maxdepth 1 -type f -exec sh -c 'echo "<a href=\"{}\">$(basename {})</a>"' \;` : this maxdepth flag can be used to list files only in current directroy and not go any deeper in those subdirectories
|
||||
- cp command
|
||||
to copy folder contents along with hidden files use the period(.) symbol too
|
||||
`cp -ar assets/. backup/` a is for archive means preserving metadata
|
||||
to copy files while excluding a file or directory
|
||||
`rsync -av --progress sourcefolder /destinationfolder --exclude thefoldertoexclude --exclude anotherFolderToExclude`
|
||||
Note : files to be excluded should be relative to source directory not the current directory from where this command is executed.
|
||||
|
||||
- Changing file name based on pattern
|
||||
|
||||
```bash
|
||||
for file in tomp3.cc*; do mv "$file" "${file/tomp3.cc - /}"
|
||||
done
|
||||
```
|
||||
- replacing names through like removing spaces
|
||||
`for f in *\ *; do mv "$f" "${f// /_}"; done`
|
||||
Though it's not recursive, it's quite fast and simple. I'm sure someone here could update it to be recursive.
|
||||
The `${f// /_}` part utilizes bash's parameter expansion mechanism to replace a pattern within a parameter with supplied string. The relevant syntax is `${parameter/pattern/string}`. See: https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html or http://wiki.bash-hackers.org/syntax/pe .
|
||||
- sort file names
|
||||
on basis of names
|
||||
- ascending order
|
||||
`ls *.jpg | sort -n`
|
||||
- descending order
|
||||
`ls *.jpg | sort -nr`
|
||||
|
||||
|
||||
- get ip address
|
||||
`ip addr` or `ifconfig`
|
||||
|
||||
- cat command
|
||||
1. `cat notes.txt` : to show contents of notes,txt
|
||||
2. `>` this will represent the transfer of data from left to right. If left side is empty then transfer from stdin to the file. All content of file will be replaced with stdin or whatever file on left.
|
||||
```bash
|
||||
cat > notes.txt
|
||||
> hey there
|
||||
>^C
|
||||
> cat notes.txt
|
||||
> hey there
|
||||
```
|
||||
3. `>>` will append data from left to right instead of truncaing it
|
||||
```bash
|
||||
cat >> notes.txt
|
||||
> hey there
|
||||
>^C
|
||||
> cat >> notes.txt
|
||||
> how r you
|
||||
>^C
|
||||
> cat notes.txt
|
||||
> hey there
|
||||
> how r you
|
||||
```
|
||||
|
||||
- aliases and function
|
||||
1. Functions
|
||||
```
|
||||
function packagelist {
|
||||
dpkg -l | grep "$1" | awk '{print $2}' | tr "\n" " "
|
||||
}
|
||||
packagelist gcc
|
||||
```
|
||||
Output:
|
||||
|
||||
|
||||

|
||||
|
||||
- Docs
|
||||
Install tldr package to get nicer docs. or tealdeer which is rust based
|
||||
|
||||
- Some utilties info
|
||||
tty is the terminal device a process is connected to
|
||||
it can be a physical terminal or a pseudo terminal
|
||||
`ps` is a command that displays process information
|
||||
and `tail` prints to output the last contents of a file
|
||||
by default the last 10 lines
|
||||
|
||||
`ps -eo user= | sort | uniq -c`
|
||||
one-liner counts the number of processes per user on the system
|
||||
ps -eo user= extracts only usernames with no header line (the '=' clears the custom header, which suppresses the header line entirely), sort arranges them, uniq -c counts processes per user. Without '=', the header row 'USER' itself would be counted as one entry.
|
||||
|
||||
- Check memory info
|
||||
`free -m`
|
||||
|
||||
- Check battery status
|
||||
To list devices
|
||||
`upower -e`
|
||||
Find battery one and get the result
|
||||
`upower -i /org/freedesktop/UPower/devices/battery_BAT0`
|
||||
|
||||
- Check desktop manager
|
||||
`systemctl list-units | grep dm.service`
|
||||
|
||||
- Check whether xorg or wayland display server
|
||||
`echo $XDG_SESSION_TYPE`
|
||||
|
||||
- last argument access
|
||||
For eg if u have used
|
||||
`mkdir test`
|
||||
Then `$_` will represent `test`
|
||||
So
|
||||
`cd $_` = `cd test`
|
||||
|
||||
- for checking CPU architecture use
|
||||
`uname -m`
|
||||
|
||||
- zswap
|
||||
compresses ram istead of using storage space
|
||||
- search for packages : pinned
|
||||
`find /usr -name '*mingw*'`
|
||||
- script for mounting multiple partitions
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
name1="mint"
|
||||
name2="manjaro"
|
||||
name3="hdd"
|
||||
name4="ssd"
|
||||
|
||||
|
||||
# Define partitions and mount points
|
||||
partition1="/dev/sda5" # mint
|
||||
partition2="/dev/sda6" # manjaro
|
||||
partition3="/dev/sda3" # hdd
|
||||
partition4="/dev/nvme0n1p3" # ssd
|
||||
mount_point1="/mnt/$name1"
|
||||
mount_point2="/mnt/$name2"
|
||||
mount_point3="/mnt/$name3"
|
||||
mount_point4="/mnt/$name4"
|
||||
|
||||
# Check if partitions are not mounted
|
||||
if ! mountpoint -q "$mount_point1"; then
|
||||
mkdir -p /mnt/$name1
|
||||
# Mount partition1
|
||||
sudo mount "$partition1" "$mount_point1"
|
||||
echo "Mounted $partition1 at $mount_point1"
|
||||
fi
|
||||
|
||||
if ! mountpoint -q "$mount_point2"; then
|
||||
mkdir -p /mnt/$name2
|
||||
# Mount partition2
|
||||
sudo mount "$partition2" "$mount_point2"
|
||||
echo "Mounted $partition2 at $mount_point2"
|
||||
fi
|
||||
|
||||
if ! mountpoint -q "$mount_point3"; then
|
||||
mkdir -p /mnt/$name3
|
||||
# Mount partition3
|
||||
sudo mount "$partition3" "$mount_point3"
|
||||
echo "Mounted $partition3 at $mount_point3"
|
||||
fi
|
||||
|
||||
if ! mountpoint -q "$mount_point4"; then
|
||||
mkdir -p /mnt/$name4
|
||||
# Mount partition4
|
||||
sudo mount "$partition4" "$mount_point4"
|
||||
echo "Mounted $partition4 at $mount_point4"
|
||||
fi
|
||||
|
||||
```
|
||||
|
||||
- size of folders and files
|
||||
The `du` command in Linux is a powerful utility that allows users to analyze and report on disk usage within directories and files.
|
||||
The basic syntax of the du command is as follows:
|
||||
|
||||
`du [options] [directory/file]`
|
||||
eg : `du -sh dir_name`
|
||||
- copy all files to next folder with exlcuding some directories say `src`
|
||||
`rsync -av --exclude='src' . ~/cache_bkp`
|
||||
`.` here is source and `~/cache_bkp` is destination
|
||||
- to prepend text
|
||||
// this way is working
|
||||
`echo -e "your text to prepend\n$(cat sample.txt)" > sample.txt`
|
||||
for large files
|
||||
```bash
|
||||
echo "your text to prepend" > temp.txt
|
||||
cat sample.txt >> temp.txt
|
||||
mv temp.txt sample.txt
|
||||
```
|
||||
// below way isnt working
|
||||
`cat - stringToBePrepended | tee -a sample.txt.`
|
||||
cat - reads from standard input (in this case, the stringToBePrepended).
|
||||
Step 2:
|
||||
Pipes the output of cat - text.txt to the next command.
|
||||
Step 3: tee -a sample.txt
|
||||
tee -a appends the input to the sample.txt file.
|
||||
The -a option tells tee to append to the file instead of overwriting it.
|
||||
Overall effect:
|
||||
The cat - text.txt | tee -a sample.txt command reads the contents of text.txt, appends them to sample.txt, and also outputs them to the terminal. This effectively prepends the contents of text.txt to sample.txt.
|
||||
Harsh Truth
|
||||
—
|
||||
Today at 12:20 AM
|
||||
|
||||
- Looping thorugh all arguments in bash
|
||||
```bash
|
||||
for arg in "$@"; do
|
||||
echo "arg: $arg"
|
||||
done
|
||||
```
|
||||
- Detecting flags in bash
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Loop through all the arguments
|
||||
for arg in "$@"; do
|
||||
case $arg in
|
||||
-a|--optionA)
|
||||
echo "Option A detected!"
|
||||
# handle option A
|
||||
;;
|
||||
-b|--optionB)
|
||||
echo "Option B detected!"
|
||||
# handle option B
|
||||
;;
|
||||
*)
|
||||
# Handle positional arguments or invalid flags
|
||||
;;
|
||||
esac
|
||||
done
|
||||
```
|
||||
- sed
|
||||
`sed -i 's/\(<string>\)\.md/\1/' your_file.txt`
|
||||
This command captures the `<string>` before .md using parentheses and then replaces the entire match (including .md) with just `<string>`, effectively removing the .md extension when it follows `<string>`.
|
||||
- Copy multiple files to a directory
|
||||
`cp -t path/to/destination_directory path/to/file1 path/to/file2 ...`
|
||||
- Copy multiple directories to a directory(copy `dir1` `dir2` to `targetDir`)
|
||||
`cp -r dir1 dir2 targetDir/`
|
||||
- Move multiple directories to directory
|
||||
`mv -t path/to/destination_directory path/to/file1 path/to/file2 ...`
|
||||
- Login to different user
|
||||
`sudo su - <user_name>` and `exit` to exit
|
||||
- User management
|
||||
https://www.freecodecamp.org/news/how-to-manage-users-in-linux/
|
||||
- Adding user
|
||||
`useradd -u 1002 -d /home/john -s /bin/bash john`
|
||||
or
|
||||
`useradd -u 1002 -d /home/john -s /bin/bash john -g johnGroup -c comments`
|
||||
- Getting user names
|
||||
Users and their other informatio separated by colons can be accessed by
|
||||
`cat /etc/passwd`
|
||||
To get only users
|
||||
`awk -F: '{ print $1}' /etc/passwd`
|
||||
Get users which can be logined
|
||||
`getent passwd {1000..60000}`
|
||||
1000 is min UID and 60000 is max UID. They may be different so find them using
|
||||
`grep -E '^UID_MIN|^UID_MAX' /etc/login.defs`
|
||||
following for users with uid and gid
|
||||
`cut -d: -f1-4 /etc/passwd`
|
||||
- Getting group names
|
||||
`cat /etc/group`
|
||||
or
|
||||
`cut -d: -f1 /etc/group | sort` (for readable form)
|
||||
- get group names for a user
|
||||
`groups $USER`
|
||||
`id $USER`
|
||||
- Password setup
|
||||
After creatiing user before login in we can setup password by
|
||||
`sudo passwd john`
|
||||
- Adding permissions
|
||||
By default when user is created he dont have permission to write anything there so he cant create any directory or file too in his own home directory. Before login in type this
|
||||
`sudo chown test:test /home/test`
|
||||
|
||||
- Adding user to group
|
||||
https://serverfault.com/questions/688685/usermod-ag-vs-gpasswd-a-as-a-best-practice
|
||||
`sudo gpasswd -a $USER groupname`
|
||||
or
|
||||
`sudo usermod -aG groupname username`
|
||||
or for adding user to multiple groups
|
||||
`sudo usermod -aG additional_groups username`
|
||||
`additional_groups` : comma separated list of groups
|
||||
- Ensure group changes to take effect
|
||||
`newgrp group_name`
|
||||
- Allowing user to use sudo
|
||||
Uncomment the line starring `$ sudo ...` then
|
||||
`sudo usermod -aG sudo username` so add user to sudo group
|
||||
`-aG` means adding user to group
|
||||
or use
|
||||
`sudo usermod -aG wheel username` if u dont wanna uncomment sudo and use wheel instead
|
||||
wheel will grant user priviledge to use sudo command
|
||||
To remove users from group 'wheel'
|
||||
`sudo gpasswd -d username wheel`
|
||||
- Changing ownership
|
||||
`chown -c john file.txt` (for users)
|
||||
or
|
||||
`chown -c :johnGroup file.txt` (for groups)
|
||||
`-c` for reporting
|
||||
for directories use
|
||||
`chown -R -c john file.txt` (for users)
|
||||
- Running command as different user without login
|
||||
`su - username -c 'command'`
|
||||
or
|
||||
`sudo -u username command`
|
||||
- Granting permissions
|
||||
to all root access priviledges to the user then
|
||||
add this to sudoers file (location : /etc/sudoers)
|
||||
`username ALL=(ALL:ALL) ALL` (very dangerous config so avoid it as much as possible as it will grant nlimited access too)
|
||||
when installing distro first user can use cd or ls command in directories without use of sudo so do this
|
||||
`sudo usermod -aG autologin $USER` to add ability as same of first user
|
||||
if it doesnt work then check permissions and using chmod change
|
||||
- Extended partition. access grant of directory can be `drwxr-x--x+` here `+` at end stands for extended permissions means other user cant access its directories even if is set `x` permission in others. Extended permissions is honored by fish shell but not bash shell may not honor it. to change it use `setfactl` and to get its detail use `getfactl`
|
||||
To add extended permissions use
|
||||
`setfacl -R u:user2:wrx /tmp`
|
||||
to remove
|
||||
`setfacl -bn /tmp`
|
||||
- to check permissions of directory simply instead of all files in it use `ls -ld <dirpath>`
|
||||
- For searching files
|
||||
`find /home/user/ | grep filenamehere`
|
||||
- launch other user files with this
|
||||
`sudo -e /path/to/other/users/binary`
|
||||
`-e` preserves your current user's environment variables etc. so audio should work
|
||||
- change to new user
|
||||
`sudo su - test`
|
||||
- for searching files with particular extension also listing their meta data
|
||||
`find . -type f -name "*.ess" -exec ls -l {} +`
|
||||
- for searching with min length 1 mb
|
||||
`find -size +1M`
|
||||
- scrolling in terminal
|
||||
TIL that u can scroll in terminal with `SHIFT+PGUP/PGDOWN`
|
||||
- useful commands
|
||||
to count number of files in current directory
|
||||
```sh
|
||||
ls | wc -l
|
||||
```
|
||||
- tar and cpio
|
||||
cpio
|
||||
```bash
|
||||
# creating archive of text files to archive.cpio
|
||||
find *.txt | cpio -o > archive.cpio
|
||||
|
||||
# extracting content to current directory
|
||||
cpio -i < ../archive.cpio
|
||||
```
|
||||
- to search for content recurseively across all files in a directory
|
||||
`grep -r hello <directory_path>`
|
||||
- resources, basic command video
|
||||
https://youtu.be/QhvDvpyvPSE
|
||||
```txt
|
||||
Nick, tell the beginners use 'trash' instead of 'delete, to retain file availability.
|
||||
Nick, tell the beginners that 'pwd' is NOT password.
|
||||
Nick, tell the beginners that 'cd -' takes them between recent directories.
|
||||
Nick, tell the beginners that Windows says 'folders', but Linux says 'directories'.
|
||||
Nick, tell the beginners that uppercase and lowercase letters denote DIFFERENT things in Linux.
|
||||
```
|
||||
- `arp -a` to get list of all otheer ip address of systems connected to same network
|
||||
- find number of files and directories recursively in given directory
|
||||
`find . -type f | wc -l` for files
|
||||
`find . -type d | wc -l` for directories
|
||||
|
||||
- to identify distro u r using
|
||||
`cat /etc/os-release `
|
||||
- to see disk space left for each partitions
|
||||
`df -h`
|
||||
|
||||
|
||||
for resumable downloads use `-c` in wget
|
||||
`wget -c https://example.com`
|
||||
225
joplin notion extension/linux/Configuring bash autocomplete.md
Normal file
|
|
@ -0,0 +1,225 @@
|
|||
Configuring bash autocomplete
|
||||
|
||||
- Syntax highlighting in bash
|
||||
https://superuser.com/questions/304211/is-there-any-way-to-get-bash-to-have-syntax-highlighting-like-fish
|
||||
|
||||
https://github.com/akinomyoga/ble.sh
|
||||
[blesh bakup.7z](../../_resources/blesh%20bakup.7z)
|
||||
|
||||
|
||||
Run these commands
|
||||
|
||||
```bash
|
||||
$ git clone https://github.com/akinomyoga/ble.sh.git
|
||||
$ cd ble.sh
|
||||
$ make
|
||||
$ make INSDIR="$HOME/.local/share/blesh" install
|
||||
```
|
||||
Then type in this `~/.bashrc`
|
||||
```
|
||||
# bashrc
|
||||
|
||||
# Add the following line at the beginning of bashrc
|
||||
[[ $- == *i* ]] &&
|
||||
source "$HOME/.local/share/blesh/ble.sh" --attach=none
|
||||
|
||||
# ... other bashrc settings ...
|
||||
|
||||
# Add the following line at the end of bashrc
|
||||
[[ ${BLE_VERSION-} ]] && ble-attach
|
||||
|
||||
```
|
||||
|
||||
new method
|
||||
```
|
||||
# TRIAL without installation
|
||||
|
||||
git clone --recursive --depth 1 --shallow-submodules https://github.com/akinomyoga/ble.sh.git
|
||||
make -C ble.sh
|
||||
source ble.sh/out/ble.sh
|
||||
|
||||
# Quick INSTALL to BASHRC (If this doesn't work, please follow Sec 1.3)
|
||||
|
||||
git clone --recursive --depth 1 --shallow-submodules https://github.com/akinomyoga/ble.sh.git
|
||||
make -C ble.sh install PREFIX=~/.local
|
||||
echo 'source ~/.local/share/blesh/ble.sh' >> ~/.bashrc
|
||||
```
|
||||
|
||||
|
||||
Output:
|
||||
|
||||
```text
|
||||
bash make_command.sh install "out/ble.sh" "/home/hpes/.local/share/blesh/ble.sh"
|
||||
bash make_command.sh install "out/lib/keymap.emacs.sh" "/home/hpes/.local/share/blesh/lib/keymap.emacs.sh"
|
||||
bash make_command.sh install "out/lib/keymap.vi.sh" "/home/hpes/.local/share/blesh/lib/keymap.vi.sh"
|
||||
bash make_command.sh install "out/lib/keymap.vi_digraph.sh" "/home/hpes/.local/share/blesh/lib/keymap.vi_digraph.sh"
|
||||
bash make_command.sh install "out/lib/keymap.vi_digraph.txt" "/home/hpes/.local/share/blesh/lib/keymap.vi_digraph.txt"
|
||||
bash make_command.sh install "out/lib/init-term.sh" "/home/hpes/.local/share/blesh/lib/init-term.sh"
|
||||
bash make_command.sh install "out/lib/init-bind.sh" "/home/hpes/.local/share/blesh/lib/init-bind.sh"
|
||||
bash make_command.sh install "out/lib/init-cmap.sh" "/home/hpes/.local/share/blesh/lib/init-cmap.sh"
|
||||
bash make_command.sh install "out/lib/init-msys1.sh" "/home/hpes/.local/share/blesh/lib/init-msys1.sh"
|
||||
bash make_command.sh install "out/lib/core-complete.sh" "/home/hpes/.local/share/blesh/lib/core-complete.sh"
|
||||
bash make_command.sh install "out/lib/core-syntax.sh" "/home/hpes/.local/share/blesh/lib/core-syntax.sh"
|
||||
bash make_command.sh install "out/lib/core-test.sh" "/home/hpes/.local/share/blesh/lib/core-test.sh"
|
||||
bash make_command.sh install "out/lib/core-cmdspec.sh" "/home/hpes/.local/share/blesh/lib/core-cmdspec.sh"
|
||||
bash make_command.sh install "out/lib/core-debug.sh" "/home/hpes/.local/share/blesh/lib/core-debug.sh"
|
||||
bash make_command.sh install "out/lib/core-edit.ignoreeof-messages.txt" "/home/hpes/.local/share/blesh/lib/core-edit.ignoreeof-messages.txt"
|
||||
bash make_command.sh install "out/lib/core-decode.emacs-rlfunc.txt" "/home/hpes/.local/share/blesh/lib/core-decode.emacs-rlfunc.txt"
|
||||
bash make_command.sh install "out/lib/core-decode.vi_imap-rlfunc.txt" "/home/hpes/.local/share/blesh/lib/core-decode.vi_imap-rlfunc.txt"
|
||||
bash make_command.sh install "out/lib/core-decode.vi_nmap-rlfunc.txt" "/home/hpes/.local/share/blesh/lib/core-decode.vi_nmap-rlfunc.txt"
|
||||
bash make_command.sh install "out/lib/vim-surround.sh" "/home/hpes/.local/share/blesh/lib/vim-surround.sh"
|
||||
bash make_command.sh install "out/lib/vim-arpeggio.sh" "/home/hpes/.local/share/blesh/lib/vim-arpeggio.sh"
|
||||
bash make_command.sh install "out/lib/vim-airline.sh" "/home/hpes/.local/share/blesh/lib/vim-airline.sh"
|
||||
bash make_command.sh install "out/lib/test-bash.sh" "/home/hpes/.local/share/blesh/lib/test-bash.sh"
|
||||
bash make_command.sh install "out/lib/test-main.sh" "/home/hpes/.local/share/blesh/lib/test-main.sh"
|
||||
bash make_command.sh install "out/lib/test-util.sh" "/home/hpes/.local/share/blesh/lib/test-util.sh"
|
||||
bash make_command.sh install "out/lib/test-canvas.sh" "/home/hpes/.local/share/blesh/lib/test-canvas.sh"
|
||||
bash make_command.sh install "out/lib/test-decode.sh" "/home/hpes/.local/share/blesh/lib/test-decode.sh"
|
||||
bash make_command.sh install "out/lib/test-edit.sh" "/home/hpes/.local/share/blesh/lib/test-edit.sh"
|
||||
bash make_command.sh install "out/lib/test-syntax.sh" "/home/hpes/.local/share/blesh/lib/test-syntax.sh"
|
||||
bash make_command.sh install "out/lib/test-complete.sh" "/home/hpes/.local/share/blesh/lib/test-complete.sh"
|
||||
bash make_command.sh install "out/lib/test-keymap.vi.sh" "/home/hpes/.local/share/blesh/lib/test-keymap.vi.sh"
|
||||
bash make_command.sh install "out/lib/util.bgproc.sh" "/home/hpes/.local/share/blesh/lib/util.bgproc.sh"
|
||||
bash make_command.sh install "out/lib/benchmark.ksh" "/home/hpes/.local/share/blesh/lib/benchmark.ksh"
|
||||
bash make_command.sh install "out/contrib/colorglass.bash" "/home/hpes/.local/share/blesh/contrib/colorglass.bash"
|
||||
bash make_command.sh install "out/contrib/histdb.bash" "/home/hpes/.local/share/blesh/contrib/histdb.bash"
|
||||
bash make_command.sh install "out/contrib/prompt-defer.bash" "/home/hpes/.local/share/blesh/contrib/prompt-defer.bash"
|
||||
bash make_command.sh install "out/contrib/prompt-elapsed.bash" "/home/hpes/.local/share/blesh/contrib/prompt-elapsed.bash"
|
||||
bash make_command.sh install "out/contrib/prompt-git.bash" "/home/hpes/.local/share/blesh/contrib/prompt-git.bash"
|
||||
bash make_command.sh install "out/contrib/prompt-vim-mode.bash" "/home/hpes/.local/share/blesh/contrib/prompt-vim-mode.bash"
|
||||
bash make_command.sh install "out/contrib/airline/atomic.bash" "/home/hpes/.local/share/blesh/contrib/airline/atomic.bash"
|
||||
bash make_command.sh install "out/contrib/airline/dark.bash" "/home/hpes/.local/share/blesh/contrib/airline/dark.bash"
|
||||
bash make_command.sh install "out/contrib/airline/dark_minimal.bash" "/home/hpes/.local/share/blesh/contrib/airline/dark_minimal.bash"
|
||||
bash make_command.sh install "out/contrib/airline/google_dark.bash" "/home/hpes/.local/share/blesh/contrib/airline/google_dark.bash"
|
||||
bash make_command.sh install "out/contrib/airline/google_light.bash" "/home/hpes/.local/share/blesh/contrib/airline/google_light.bash"
|
||||
bash make_command.sh install "out/contrib/airline/landscape.bash" "/home/hpes/.local/share/blesh/contrib/airline/landscape.bash"
|
||||
bash make_command.sh install "out/contrib/airline/light.bash" "/home/hpes/.local/share/blesh/contrib/airline/light.bash"
|
||||
bash make_command.sh install "out/contrib/airline/minimalist.bash" "/home/hpes/.local/share/blesh/contrib/airline/minimalist.bash"
|
||||
bash make_command.sh install "out/contrib/airline/monochrome.bash" "/home/hpes/.local/share/blesh/contrib/airline/monochrome.bash"
|
||||
bash make_command.sh install "out/contrib/airline/solarized.bash" "/home/hpes/.local/share/blesh/contrib/airline/solarized.bash"
|
||||
bash make_command.sh install "out/contrib/airline/solarized_flood.bash" "/home/hpes/.local/share/blesh/contrib/airline/solarized_flood.bash"
|
||||
bash make_command.sh install "out/contrib/airline/term.bash" "/home/hpes/.local/share/blesh/contrib/airline/term.bash"
|
||||
bash make_command.sh install "out/contrib/airline/term_light.bash" "/home/hpes/.local/share/blesh/contrib/airline/term_light.bash"
|
||||
bash make_command.sh install "out/contrib/airline/transparent.bash" "/home/hpes/.local/share/blesh/contrib/airline/transparent.bash"
|
||||
bash make_command.sh install "out/contrib/airline/xtermlight.bash" "/home/hpes/.local/share/blesh/contrib/airline/xtermlight.bash"
|
||||
bash make_command.sh install "out/contrib/config/execmark.bash" "/home/hpes/.local/share/blesh/contrib/config/execmark.bash"
|
||||
bash make_command.sh install "out/contrib/config/github265-prompt-path-level-colors.bash" "/home/hpes/.local/share/blesh/contrib/config/github265-prompt-path-level-colors.bash"
|
||||
bash make_command.sh install "out/contrib/config/github288-filter-sabbrev-completion.bash" "/home/hpes/.local/share/blesh/contrib/config/github288-filter-sabbrev-completion.bash"
|
||||
bash make_command.sh install "out/contrib/config/github296-named-execmark.bash" "/home/hpes/.local/share/blesh/contrib/config/github296-named-execmark.bash"
|
||||
bash make_command.sh install "out/contrib/config/github302-perlre-server.bash" "/home/hpes/.local/share/blesh/contrib/config/github302-perlre-server.bash"
|
||||
bash make_command.sh install "out/contrib/integration/bash-preexec.bash" "/home/hpes/.local/share/blesh/contrib/integration/bash-preexec.bash"
|
||||
bash make_command.sh install "out/contrib/integration/fzf-completion.bash" "/home/hpes/.local/share/blesh/contrib/integration/fzf-completion.bash"
|
||||
bash make_command.sh install "out/contrib/integration/fzf-git.bash" "/home/hpes/.local/share/blesh/contrib/integration/fzf-git.bash"
|
||||
bash make_command.sh install "out/contrib/integration/fzf-initialize.bash" "/home/hpes/.local/share/blesh/contrib/integration/fzf-initialize.bash"
|
||||
bash make_command.sh install "out/contrib/integration/fzf-key-bindings.bash" "/home/hpes/.local/share/blesh/contrib/integration/fzf-key-bindings.bash"
|
||||
bash make_command.sh install "out/contrib/integration/nix-completion.bash" "/home/hpes/.local/share/blesh/contrib/integration/nix-completion.bash"
|
||||
bash make_command.sh install "out/contrib/integration/zoxide.bash" "/home/hpes/.local/share/blesh/contrib/integration/zoxide.bash"
|
||||
bash make_command.sh install "out/contrib/layer/pattern.bash" "/home/hpes/.local/share/blesh/contrib/layer/pattern.bash"
|
||||
bash make_command.sh install "out/contrib/layer/sample.adapter.bash" "/home/hpes/.local/share/blesh/contrib/layer/sample.adapter.bash"
|
||||
bash make_command.sh install "out/contrib/layer/sample.RandomColor2.bash" "/home/hpes/.local/share/blesh/contrib/layer/sample.RandomColor2.bash"
|
||||
bash make_command.sh install "out/contrib/layer/sample.RandomColor.bash" "/home/hpes/.local/share/blesh/contrib/layer/sample.RandomColor.bash"
|
||||
bash make_command.sh install "out/contrib/bash-preexec.bash" "/home/hpes/.local/share/blesh/contrib/bash-preexec.bash"
|
||||
bash make_command.sh install "out/contrib/fzf-completion.bash" "/home/hpes/.local/share/blesh/contrib/fzf-completion.bash"
|
||||
bash make_command.sh install "out/contrib/fzf-git.bash" "/home/hpes/.local/share/blesh/contrib/fzf-git.bash"
|
||||
bash make_command.sh install "out/contrib/fzf-initialize.bash" "/home/hpes/.local/share/blesh/contrib/fzf-initialize.bash"
|
||||
bash make_command.sh install "out/contrib/fzf-key-bindings.bash" "/home/hpes/.local/share/blesh/contrib/fzf-key-bindings.bash"
|
||||
bash make_command.sh install "out/doc/README.md" "/home/hpes/.local/share/doc/blesh/README.md"
|
||||
bash make_command.sh install "out/doc/README-ja_JP.md" "/home/hpes/.local/share/doc/blesh/README-ja_JP.md"
|
||||
bash make_command.sh install "out/doc/CONTRIBUTING.md" "/home/hpes/.local/share/doc/blesh/CONTRIBUTING.md"
|
||||
bash make_command.sh install "out/doc/ChangeLog.md" "/home/hpes/.local/share/doc/blesh/ChangeLog.md"
|
||||
bash make_command.sh install "out/doc/Release.md" "/home/hpes/.local/share/doc/blesh/Release.md"
|
||||
bash make_command.sh install "out/doc/contrib/README-ja.md" "/home/hpes/.local/share/doc/blesh/contrib/README-ja.md"
|
||||
bash make_command.sh install "out/doc/contrib/README.md" "/home/hpes/.local/share/doc/blesh/contrib/README.md"
|
||||
bash make_command.sh install "out/doc/LICENSE.md" "/home/hpes/.local/share/doc/blesh/LICENSE.md"
|
||||
bash make_command.sh install "out/doc/contrib/LICENSE" "/home/hpes/.local/share/doc/blesh/contrib/LICENSE"
|
||||
mkdir -p /home/hpes/.local/share/blesh/cache.d && chmod a+rwxt /home/hpes/.local/share/blesh/cache.d
|
||||
mkdir -p /home/hpes/.local/share/blesh/run && chmod a+rwxt /home/hpes/.local/share/blesh/run
|
||||
```
|
||||
when using insdir flag
|
||||
```
|
||||
bash make_command.sh install "out/ble.sh" "/home/snappy/.local/share/blesh/ble.sh"
|
||||
bash make_command.sh install "out/lib/keymap.emacs.sh" "/home/snappy/.local/share/blesh/lib/keymap.emacs.sh"
|
||||
bash make_command.sh install "out/lib/keymap.vi.sh" "/home/snappy/.local/share/blesh/lib/keymap.vi.sh"
|
||||
bash make_command.sh install "out/lib/keymap.vi_digraph.sh" "/home/snappy/.local/share/blesh/lib/keymap.vi_digraph.sh"
|
||||
bash make_command.sh install "out/lib/keymap.vi_digraph.txt" "/home/snappy/.local/share/blesh/lib/keymap.vi_digraph.txt"
|
||||
bash make_command.sh install "out/lib/init-term.sh" "/home/snappy/.local/share/blesh/lib/init-term.sh"
|
||||
bash make_command.sh install "out/lib/init-bind.sh" "/home/snappy/.local/share/blesh/lib/init-bind.sh"
|
||||
bash make_command.sh install "out/lib/init-cmap.sh" "/home/snappy/.local/share/blesh/lib/init-cmap.sh"
|
||||
bash make_command.sh install "out/lib/init-msys1.sh" "/home/snappy/.local/share/blesh/lib/init-msys1.sh"
|
||||
bash make_command.sh install "out/lib/core-complete.sh" "/home/snappy/.local/share/blesh/lib/core-complete.sh"
|
||||
bash make_command.sh install "out/lib/core-syntax.sh" "/home/snappy/.local/share/blesh/lib/core-syntax.sh"
|
||||
bash make_command.sh install "out/lib/core-test.sh" "/home/snappy/.local/share/blesh/lib/core-test.sh"
|
||||
bash make_command.sh install "out/lib/core-cmdspec.sh" "/home/snappy/.local/share/blesh/lib/core-cmdspec.sh"
|
||||
bash make_command.sh install "out/lib/core-debug.sh" "/home/snappy/.local/share/blesh/lib/core-debug.sh"
|
||||
bash make_command.sh install "out/lib/core-edit.ignoreeof-messages.txt" "/home/snappy/.local/share/blesh/lib/core-edit.ignoreeof-messages.txt"
|
||||
bash make_command.sh install "out/lib/core-decode.emacs-rlfunc.txt" "/home/snappy/.local/share/blesh/lib/core-decode.emacs-rlfunc.txt"
|
||||
bash make_command.sh install "out/lib/core-decode.vi_imap-rlfunc.txt" "/home/snappy/.local/share/blesh/lib/core-decode.vi_imap-rlfunc.txt"
|
||||
bash make_command.sh install "out/lib/core-decode.vi_nmap-rlfunc.txt" "/home/snappy/.local/share/blesh/lib/core-decode.vi_nmap-rlfunc.txt"
|
||||
bash make_command.sh install "out/lib/vim-surround.sh" "/home/snappy/.local/share/blesh/lib/vim-surround.sh"
|
||||
bash make_command.sh install "out/lib/vim-arpeggio.sh" "/home/snappy/.local/share/blesh/lib/vim-arpeggio.sh"
|
||||
bash make_command.sh install "out/lib/vim-airline.sh" "/home/snappy/.local/share/blesh/lib/vim-airline.sh"
|
||||
bash make_command.sh install "out/lib/test-bash.sh" "/home/snappy/.local/share/blesh/lib/test-bash.sh"
|
||||
bash make_command.sh install "out/lib/test-main.sh" "/home/snappy/.local/share/blesh/lib/test-main.sh"
|
||||
bash make_command.sh install "out/lib/test-util.sh" "/home/snappy/.local/share/blesh/lib/test-util.sh"
|
||||
bash make_command.sh install "out/lib/test-canvas.sh" "/home/snappy/.local/share/blesh/lib/test-canvas.sh"
|
||||
bash make_command.sh install "out/lib/test-decode.sh" "/home/snappy/.local/share/blesh/lib/test-decode.sh"
|
||||
bash make_command.sh install "out/lib/test-edit.sh" "/home/snappy/.local/share/blesh/lib/test-edit.sh"
|
||||
bash make_command.sh install "out/lib/test-syntax.sh" "/home/snappy/.local/share/blesh/lib/test-syntax.sh"
|
||||
bash make_command.sh install "out/lib/test-complete.sh" "/home/snappy/.local/share/blesh/lib/test-complete.sh"
|
||||
bash make_command.sh install "out/lib/test-keymap.vi.sh" "/home/snappy/.local/share/blesh/lib/test-keymap.vi.sh"
|
||||
bash make_command.sh install "out/lib/util.bgproc.sh" "/home/snappy/.local/share/blesh/lib/util.bgproc.sh"
|
||||
bash make_command.sh install "out/lib/benchmark.ksh" "/home/snappy/.local/share/blesh/lib/benchmark.ksh"
|
||||
bash make_command.sh install "out/contrib/colorglass.bash" "/home/snappy/.local/share/blesh/contrib/colorglass.bash"
|
||||
bash make_command.sh install "out/contrib/histdb.bash" "/home/snappy/.local/share/blesh/contrib/histdb.bash"
|
||||
bash make_command.sh install "out/contrib/prompt-defer.bash" "/home/snappy/.local/share/blesh/contrib/prompt-defer.bash"
|
||||
bash make_command.sh install "out/contrib/prompt-elapsed.bash" "/home/snappy/.local/share/blesh/contrib/prompt-elapsed.bash"
|
||||
bash make_command.sh install "out/contrib/prompt-git.bash" "/home/snappy/.local/share/blesh/contrib/prompt-git.bash"
|
||||
bash make_command.sh install "out/contrib/prompt-vim-mode.bash" "/home/snappy/.local/share/blesh/contrib/prompt-vim-mode.bash"
|
||||
bash make_command.sh install "out/contrib/airline/atomic.bash" "/home/snappy/.local/share/blesh/contrib/airline/atomic.bash"
|
||||
bash make_command.sh install "out/contrib/airline/dark.bash" "/home/snappy/.local/share/blesh/contrib/airline/dark.bash"
|
||||
bash make_command.sh install "out/contrib/airline/dark_minimal.bash" "/home/snappy/.local/share/blesh/contrib/airline/dark_minimal.bash"
|
||||
bash make_command.sh install "out/contrib/airline/google_dark.bash" "/home/snappy/.local/share/blesh/contrib/airline/google_dark.bash"
|
||||
bash make_command.sh install "out/contrib/airline/google_light.bash" "/home/snappy/.local/share/blesh/contrib/airline/google_light.bash"
|
||||
bash make_command.sh install "out/contrib/airline/landscape.bash" "/home/snappy/.local/share/blesh/contrib/airline/landscape.bash"
|
||||
bash make_command.sh install "out/contrib/airline/light.bash" "/home/snappy/.local/share/blesh/contrib/airline/light.bash"
|
||||
bash make_command.sh install "out/contrib/airline/minimalist.bash" "/home/snappy/.local/share/blesh/contrib/airline/minimalist.bash"
|
||||
bash make_command.sh install "out/contrib/airline/monochrome.bash" "/home/snappy/.local/share/blesh/contrib/airline/monochrome.bash"
|
||||
bash make_command.sh install "out/contrib/airline/solarized.bash" "/home/snappy/.local/share/blesh/contrib/airline/solarized.bash"
|
||||
bash make_command.sh install "out/contrib/airline/solarized_flood.bash" "/home/snappy/.local/share/blesh/contrib/airline/solarized_flood.bash"
|
||||
bash make_command.sh install "out/contrib/airline/term.bash" "/home/snappy/.local/share/blesh/contrib/airline/term.bash"
|
||||
bash make_command.sh install "out/contrib/airline/term_light.bash" "/home/snappy/.local/share/blesh/contrib/airline/term_light.bash"
|
||||
bash make_command.sh install "out/contrib/airline/transparent.bash" "/home/snappy/.local/share/blesh/contrib/airline/transparent.bash"
|
||||
bash make_command.sh install "out/contrib/airline/xtermlight.bash" "/home/snappy/.local/share/blesh/contrib/airline/xtermlight.bash"
|
||||
bash make_command.sh install "out/contrib/config/execmark.bash" "/home/snappy/.local/share/blesh/contrib/config/execmark.bash"
|
||||
bash make_command.sh install "out/contrib/config/github265-prompt-path-level-colors.bash" "/home/snappy/.local/share/blesh/contrib/config/github265-prompt-path-level-colors.bash"
|
||||
bash make_command.sh install "out/contrib/config/github288-filter-sabbrev-completion.bash" "/home/snappy/.local/share/blesh/contrib/config/github288-filter-sabbrev-completion.bash"
|
||||
bash make_command.sh install "out/contrib/config/github296-named-execmark.bash" "/home/snappy/.local/share/blesh/contrib/config/github296-named-execmark.bash"
|
||||
bash make_command.sh install "out/contrib/config/github302-perlre-server.bash" "/home/snappy/.local/share/blesh/contrib/config/github302-perlre-server.bash"
|
||||
bash make_command.sh install "out/contrib/integration/bash-preexec.bash" "/home/snappy/.local/share/blesh/contrib/integration/bash-preexec.bash"
|
||||
bash make_command.sh install "out/contrib/integration/fzf-completion.bash" "/home/snappy/.local/share/blesh/contrib/integration/fzf-completion.bash"
|
||||
bash make_command.sh install "out/contrib/integration/fzf-git.bash" "/home/snappy/.local/share/blesh/contrib/integration/fzf-git.bash"
|
||||
bash make_command.sh install "out/contrib/integration/fzf-initialize.bash" "/home/snappy/.local/share/blesh/contrib/integration/fzf-initialize.bash"
|
||||
bash make_command.sh install "out/contrib/integration/fzf-key-bindings.bash" "/home/snappy/.local/share/blesh/contrib/integration/fzf-key-bindings.bash"
|
||||
bash make_command.sh install "out/contrib/integration/nix-completion.bash" "/home/snappy/.local/share/blesh/contrib/integration/nix-completion.bash"
|
||||
bash make_command.sh install "out/contrib/integration/zoxide.bash" "/home/snappy/.local/share/blesh/contrib/integration/zoxide.bash"
|
||||
bash make_command.sh install "out/contrib/layer/pattern.bash" "/home/snappy/.local/share/blesh/contrib/layer/pattern.bash"
|
||||
bash make_command.sh install "out/contrib/layer/sample.adapter.bash" "/home/snappy/.local/share/blesh/contrib/layer/sample.adapter.bash"
|
||||
bash make_command.sh install "out/contrib/layer/sample.RandomColor2.bash" "/home/snappy/.local/share/blesh/contrib/layer/sample.RandomColor2.bash"
|
||||
bash make_command.sh install "out/contrib/layer/sample.RandomColor.bash" "/home/snappy/.local/share/blesh/contrib/layer/sample.RandomColor.bash"
|
||||
bash make_command.sh install "out/contrib/bash-preexec.bash" "/home/snappy/.local/share/blesh/contrib/bash-preexec.bash"
|
||||
bash make_command.sh install "out/contrib/fzf-completion.bash" "/home/snappy/.local/share/blesh/contrib/fzf-completion.bash"
|
||||
bash make_command.sh install "out/contrib/fzf-git.bash" "/home/snappy/.local/share/blesh/contrib/fzf-git.bash"
|
||||
bash make_command.sh install "out/contrib/fzf-initialize.bash" "/home/snappy/.local/share/blesh/contrib/fzf-initialize.bash"
|
||||
bash make_command.sh install "out/contrib/fzf-key-bindings.bash" "/home/snappy/.local/share/blesh/contrib/fzf-key-bindings.bash"
|
||||
bash make_command.sh install "out/doc/README.md" "/home/snappy/.local/share/blesh/doc/README.md"
|
||||
bash make_command.sh install "out/doc/README-ja_JP.md" "/home/snappy/.local/share/blesh/doc/README-ja_JP.md"
|
||||
bash make_command.sh install "out/doc/CONTRIBUTING.md" "/home/snappy/.local/share/blesh/doc/CONTRIBUTING.md"
|
||||
bash make_command.sh install "out/doc/ChangeLog.md" "/home/snappy/.local/share/blesh/doc/ChangeLog.md"
|
||||
bash make_command.sh install "out/doc/Release.md" "/home/snappy/.local/share/blesh/doc/Release.md"
|
||||
bash make_command.sh install "out/doc/contrib/README-ja.md" "/home/snappy/.local/share/blesh/doc/contrib/README-ja.md"
|
||||
bash make_command.sh install "out/doc/contrib/README.md" "/home/snappy/.local/share/blesh/doc/contrib/README.md"
|
||||
bash make_command.sh install "out/doc/LICENSE.md" "/home/snappy/.local/share/blesh/doc/LICENSE.md"
|
||||
bash make_command.sh install "out/doc/contrib/LICENSE" "/home/snappy/.local/share/blesh/doc/contrib/LICENSE"
|
||||
mkdir -p /home/snappy/.local/share/blesh/cache.d && chmod a+rwxt /home/snappy/.local/share/blesh/cache.d
|
||||
mkdir -p /home/snappy/.local/share/blesh/run && chmod a+rwxt /home/snappy/.local/share/blesh/run
|
||||
```
|
||||
24
joplin notion extension/linux/Cons.md
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
Cons
|
||||
|
||||
- wine issues
|
||||
Some applications like winrar dont run. spytify even after installing dotnet has this issue
|
||||

|
||||
|
||||
For autohotkey this error
|
||||

|
||||
|
||||
Some applications r getting this error after being installed or during install
|
||||

|
||||
|
||||
|
||||
proton doesnt fare well with mid or low end gpus though (when it comes to games like elden ring or counter strike)
|
||||
|
||||
i have an i7 with a 1060 and i cant even get counterstrike or elden ring to run without lowering the resolution to 180p and still getting stutters and low fps (while on windows they ran just fine on low-mid graphics)
|
||||
|
||||
and yes i tried options like gamemoderun, gamescope, and even got protonGE and nothing really changed sadly lmao
|
||||
Windows relies on directx while Linux relies on vulkan
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
21
joplin notion extension/linux/Distros.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
Distros
|
||||
https://distrowatch.com/search-mobile.php?ostype=All&category=All&origin=All&basedon=Independent¬basedon=None&desktop=All&architecture=All&package=All&rolling=All&isosize=All&netinstall=All&language=All&defaultinit=All&status=Active#simple
|
||||
|
||||
1. Debian, Red Hat/Fedora, SuSE, Arch, Gentoo, Slackware : main
|
||||
2. All
|
||||
[DistroWatch.com_ Put the fun back into computing. Use Linux, BSD. (23_10_2023 2_46_50 am).html](../../_resources/DistroWatch.com_%20Put%20the%20fun%20back%20into%20computing.%20.html)
|
||||
|
||||
|
||||
1. **Alpine** : Used in dockers. Alpine Linux is a Linux distribution designed to be small, simple, and secure. It uses musl, BusyBox, and OpenRC instead of the more commonly used glibc, GNU Core Utilities, and systemd. For security, Alpine compiles all user-space binaries as position-independent executables with stack-smashing protection
|
||||
2. **Android** : MobileOS
|
||||
3. **Arch linux**: It is an independently developed, x86_64-optimised Linux distribution targeted at competent Linux users. It uses 'pacman', its home-grown package manager, to provide updates to the latest software applications with full dependency tracking. Operating on a rolling release system, Arch can be installed from a CD image or via an FTP server. The default install provides a solid base that enables users to create a custom installation. In addition, the Arch Build System (ABS) provides a way to easily build new packages, modify the configuration of stock packages, and share these packages with other users via the Arch Linux user repository.
|
||||
4. **Fedora:** Fedora Linux (formerly Fedora, formerly Fedora Core) is a Linux distribution developed by the community-supported Fedora Project and owned by Red Hat. Fedora Linux contains software distributed under a free and open-source license and aims to be on the leading edge of such technologies. Fedora has a reputation for focusing on innovation, integrating new technologies early on and working closely with upstream Linux communities.
|
||||
5. **Nix OS**: NixOS is an independently developed GNU/Linux distribution that aims to improve the state of the art in system configuration management. In NixOS, the entire operating system, including the kernel, applications, system packages and configuration files, are built by the Nix package manager. Nix stores all packages in isolation from each other; as a result there are no /bin, /sbin, /lib or /usr directories and all packages are kept in /nix/store instead. Other innovative features of NixOS include reliable upgrades, rollbacks, reproducible system configurations, source-based model with binaries, and multi-user package management. Although NixOS started as a research project, it is now a functional and usable operating system that includes hardware detection, KDE as the default desktop, and systemd for managing system services.
|
||||
6. **Slackware Linux** (43)
|
||||
The Official Release of Slackware Linux by Patrick Volkerding is an advanced Linux operating system, designed with the twin goals of ease of use and stability as top priorities. Including the latest popular software while retaining a sense of tradition, providing simplicity and ease of use alongside flexibility and power, Slackware brings the best of all worlds to the table. Originally developed by Linus Torvalds in 1991, the UNIX-like Linux operating system now benefits from the contributions of millions of users and developers around the world. Slackware Linux provides new and experienced users alike with a fully-featured system, equipped to serve in any capacity from desktop workstation to machine-room server. Web, ftp, and email servers are ready to go out of the box, as are a wide selection of popular desktop environments. A full range of development tools, editors, and current libraries is included for users who wish to develop or compile additional software.
|
||||
7. **Gentoo Linux** (59)
|
||||
Gentoo Linux is a versatile and fast, completely free Linux distribution geared towards developers and network professionals. Unlike other distros, Gentoo Linux has an advanced package management system called Portage. Portage is a true ports system in the tradition of BSD ports, but is Python-based and sports a number of advanced features including dependencies, fine-grained package management, "fake" (OpenBSD-style) installs, safe unmerging, system profiles, virtual packages, config file management, and more.
|
||||
6. Void (71)
|
||||
Void is an independently-developed, general-purpose operating system based on the monolithic Linux kernel. It features a hybrid binary/source package management system which allows users to quickly install, update and remove software, or to build software directly from sources with the help of the XBPS source packages collection. Other features of the distribution include support for Raspberry Pi single-board computers (both armv6 and armv7), rolling-release development model with daily updates, and native init system called "runit".
|
||||
|
||||
|
||||
784
joplin notion extension/linux/Extras.md
Normal file
|
|
@ -0,0 +1,784 @@
|
|||
Extras
|
||||
|
||||
- aptitude
|
||||
better than `apt get`
|
||||
aptitude is a command-line package manager Basically it helps with everything related to packages like removal installation ecc...
|
||||
https://wiki.debian.org/Aptitude
|
||||
- Binary blobs in linux
|
||||
https://www.reddit.com/r/linux/comments/ui4wal/so_where_are_the_closedsource_binary_blobs_in/
|
||||
- sftp, scp
|
||||
https://superuser.com/questions/326211/best-way-to-transfer-files-over-a-lan-between-two-linux-computers
|
||||
scp tldrs
|
||||
single file
|
||||
`scp myfile.txt user@192.168.1.5:/home/user/`
|
||||
entire directory
|
||||
`scp -r my_folder/ user@192.168.1.5:/home/user/`
|
||||
flags
|
||||
`-p` : for preserving metadata
|
||||
`-P` : custom port
|
||||
`-C` : compression for saving bandwidth
|
||||
- To run .sh file as a command
|
||||
Make it executable by `chmod +x script`. also remove `.sh` extension too so it will be `script` and not `script.sh` Either add in `/usr/bin` as `$PATH` variable contain that directory or add your directory where the script is there by editing `~/.bashrc` file
|
||||
```text
|
||||
export PATH=$PATH:$HOME/<script_folder>
|
||||
```
|
||||
`$HOME` contains `home/<username>` as directory
|
||||
- ssh issue
|
||||
If u get error when trying to connect with ssh like this
|
||||
```text
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
|
||||
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
||||
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
|
||||
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
|
||||
It is also possible that a host key has just been changed.
|
||||
The fingerprint for the RSA key sent by the remote host is
|
||||
6e:45:f9:a8:af:38:3d:a1:a5:c7:76:1d:02:f8:77:00.
|
||||
Please contact your system administrator.
|
||||
Add correct host key in /home/hostname /.ssh/known_hosts to get rid of this message.
|
||||
Offending RSA key in /var/lib/sss/pubconf/known_hosts:4
|
||||
RSA host key for pong has changed and you have requested strict checking.
|
||||
Host key verification failed.
|
||||
```
|
||||
Then use the command
|
||||
`ssh-keygen -R <host>`
|
||||
Eg : `ssh-keygen -R 192.168.3.10`
|
||||
- MFT error
|
||||
When disk is of ntfs and it is unplugged unsafely then when reconnected error can be MFTmirror do not match MFT so correct it with
|
||||
`sudo ntfsfix /dev/sdb1`
|
||||
Make sure `ntfs-3g` must be installed
|
||||
- to get ip address
|
||||
`ipinfo.io`
|
||||
`ip.im`
|
||||
`ip.me`
|
||||
`curl ifconfig.co`
|
||||
`curl ifconfig.me`
|
||||
`curl icanhazip.com`
|
||||
- For getting cname use this
|
||||
`nslookup -Q=cname www.youtube.com`
|
||||
- Change DNS
|
||||
Changing the DNS server to 1.1.1.1 (Cloudflare's DNS service) in Arch Linux can provide you with faster and more private internet browsing. The specific steps to change your DNS settings can depend on whether you are using NetworkManager, systemd-resolved, or another network management tool on your Arch Linux setup. Below are methods for the two most common tools, NetworkManager and systemd-networkd with systemd-resolved:
|
||||
### For NetworkManager users:
|
||||
|
||||
1. **Using the GUI:**
|
||||
|
||||
If you're using a graphical environment, you can change the DNS settings through the NetworkManager applet.
|
||||
|
||||
- Right-click on the NetworkManager icon in the system tray and select `Edit Connections`.
|
||||
- Select the connection you want to edit and click on the `Gear` icon or `Edit` button.
|
||||
- Go to the `IPv4 Settings` or `IPv6 Settings` tab.
|
||||
- Change the `Method` to `Automatic (DHCP) addresses only` or `Manual` if you set your IP address statically.
|
||||
- Enter `1.1.1.1, 1.0.0.1` in the `DNS servers` field. For IPv6, use `2606:4700:4700::1111, 2606:4700:4700::1001`.
|
||||
- Click `Save` and close the Network Connections window.
|
||||
- Finally, disable and re-enable the network connection for the changes to take effect.
|
||||
|
||||
2. **Using the terminal:**
|
||||
|
||||
- You can also edit the NetworkManager configuration file directly for the connection. Connection profiles are stored in `/etc/NetworkManager/system-connections/`. Find the profile you wish to edit and open it with a text editor (as root). You may need to install `nano` or use another available editor.
|
||||
```bash
|
||||
sudo nano /etc/NetworkManager/system-connections/YourConnectionName.nmconnection
|
||||
```
|
||||
- Add the following lines under the `[ipv4]` or `[ipv6]` sections:
|
||||
```
|
||||
dns=1.1.1.1;1.0.0.1;
|
||||
```
|
||||
For IPv6:
|
||||
```
|
||||
dns=2606:4700:4700::1111;2606:4700:4700::1001;
|
||||
```
|
||||
- Save the changes and restart NetworkManager:
|
||||
```bash
|
||||
sudo systemctl restart NetworkManager
|
||||
```
|
||||
### For systemd-networkd with systemd-resolved users:
|
||||
|
||||
1. **Edit or Create a network file:**
|
||||
|
||||
Your network configuration files are located in `/etc/systemd/network/`. If you're using systemd-networkd for managing the network, edit the corresponding `.network` file for your connection.
|
||||
|
||||
- Open the relevant `.network` file in a text editor (as root):
|
||||
```bash
|
||||
sudo nano /etc/systemd/network/your_network_file.network
|
||||
```
|
||||
- Add or modify the following section to set Cloudflare's DNS servers:
|
||||
```
|
||||
[DHCP]
|
||||
UseDNS=false
|
||||
[Network]
|
||||
DNS=1.1.1.1
|
||||
DNS=1.0.0.1
|
||||
# For IPv6
|
||||
DNS=2606:4700:4700::1111
|
||||
DNS=2606:4700:4700::1001
|
||||
```
|
||||
- Save the file and exit the editor.
|
||||
|
||||
2. **Restart systemd-networkd and systemd-resolved:**
|
||||
|
||||
- Apply the changes by restarting the services:
|
||||
```bash
|
||||
sudo systemctl restart systemd-networkd
|
||||
sudo systemctl restart systemd-resolved
|
||||
```
|
||||
|
||||
3. **Ensure systemd-resolved is used for DNS resolution:**
|
||||
|
||||
- Create a symlink to use systemd-resolved's stub resolver:
|
||||
```bash
|
||||
sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
|
||||
```
|
||||
|
||||
Remember to replace placeholder texts like `YourConnectionName` or `your_network_file.network` with the actual names specific to your setup. Each setup might be slightly different, so adjust the steps according to your network management tool and configuration.
|
||||
|
||||
|
||||
## Supervisord
|
||||
like pm2 but not limited to nodejs
|
||||
- Create a config file for supervisord and store it anywhere
|
||||
```ini
|
||||
[supervisord]
|
||||
nodaemon=true
|
||||
|
||||
[program:app1]
|
||||
command=node /path/to/app1/app.js
|
||||
directory=/path/to/app1
|
||||
autostart=true
|
||||
autorestart=true
|
||||
stdout_logfile=/path/to/app1.log
|
||||
stderr_logfile=/path/to/app1_error.log
|
||||
|
||||
[program:app2]
|
||||
command=node /path/to/app2/app.js
|
||||
directory=/path/to/app2
|
||||
autostart=true
|
||||
autorestart=true
|
||||
stdout_logfile=/path/to/app2.log
|
||||
stderr_logfile=/path/to/app2_error.log
|
||||
```
|
||||
- Then start it with
|
||||
`sudo supervisord -c /home/user/supervisor/supervisord.conf`
|
||||
Then for interacting
|
||||
`sudo supervisorctl start app1`
|
||||
`sudo supervisorctl stop app1`
|
||||
`sudo supervisorctl restart app1`
|
||||
`sudo supervisorctl status`
|
||||
- Issues
|
||||
sometimes when using package manager supervisor may not work properly so install it with pip.
|
||||
`pip install supervisor`. sometimes if pip is not installed then upgrade your python package
|
||||
- Setting up proxy
|
||||
In `~/.bashrc` add following so that terminals can use proxy
|
||||
```bash
|
||||
export http_proxy="210.61.216.63:60808"
|
||||
export https_proxy="115.87.207.193:8080"
|
||||
```
|
||||
for systemwide add in `/etc/environemnt`.
|
||||
- `sudo systemd-analyze` : this will tell the boot time of firmware+loader+kernel+userspace
|
||||
- using proxy with curl
|
||||
` curl -x 37.27.29.181:80 ipinfo.io`
|
||||
here `37.27.29.181:80` is proxy `-x` is flag for proxy
|
||||
|
||||
|
||||
|
||||
### inotify
|
||||
Note : inotify wont work to detect changes in remote system
|
||||
https://unix.stackexchange.com/questions/238956/is-there-a-way-to-use-inotify-on-remote-filesystems-specifically-webdav
|
||||
make changes or execute script when changes on files or directory
|
||||
- install ionotify and rsync
|
||||
`sudo apt-get install inotify-tools rsync`
|
||||
- Create a script with following (for syncing directories)
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
SOURCE="/path/to/source"
|
||||
DESTINATION="/path/to/destination"
|
||||
|
||||
# Function to sync directories
|
||||
sync_directories() {
|
||||
# a for archiving(preserving metadata), v for verbose, z for compressing
|
||||
rsync -avz --delete "$SOURCE/" "$DESTINATION/"
|
||||
}
|
||||
|
||||
# Ensure initial sync
|
||||
sync_directories
|
||||
|
||||
# Monitor the source directory for any activity, and sync upon changes
|
||||
# while read -r directory events filename; do: This line starts a while loop that reads input and assigns the values to three variables: directory, events, and filename. -r option is used with read command to prevent backslashes from acting as escape characters.
|
||||
inotifywait -mre close_write,create,delete,move "$SOURCE" |
|
||||
while read -r directory events filename; do
|
||||
sync_directories
|
||||
done
|
||||
```
|
||||
finally make it executable
|
||||
`chmod +x sync_directories.sh`
|
||||
- bidirectional sync without noticing deletions ie only modifications of files will be noticed (for directories)
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
SOURCE=$1
|
||||
DESTINATION=$2
|
||||
|
||||
# Function to sync directories
|
||||
sync_directories() {
|
||||
# u means updates
|
||||
# deletions will be ignored with flag --ignore-existing
|
||||
rsync -avu --ignore-existing "$SOURCE/" "$DESTINATION/"
|
||||
}
|
||||
|
||||
sync_directories2() {
|
||||
rsync -avu --ignore-existing "$DESTINATION/" "$SOURCE/"
|
||||
}
|
||||
|
||||
# Ensure initial sync
|
||||
sync_directories
|
||||
|
||||
# Monitor the source directory for any activity, and sync upon changes
|
||||
inotifywait -mre close_write,create,delete,move "$SOURCE" |
|
||||
while read -r directory events filename; do
|
||||
sync_directories
|
||||
done
|
||||
|
||||
inotifywait -mre close_write,create,delete,move "$DESTINATION" |
|
||||
while read -r directory events filename; do
|
||||
sync_directories2
|
||||
done
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
or use unison
|
||||
Do the initial sync:
|
||||
`unison -auto -batch dirA dirB`
|
||||
|
||||
Run the continuous bidirectional sync:
|
||||
`unison -auto -batch -repeat watch -times dirA dirB`
|
||||
|
||||
|
||||
- for syncing files
|
||||
unidirectional
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
SOURCE_FILE="/path/to/source/myfile.txt"
|
||||
TARGET_FILE="/path/to/target/myfile.txt"
|
||||
|
||||
# Loop forever
|
||||
while true; do
|
||||
# Wait for modifications to the specified file
|
||||
inotifywait -e modify,move,create,delete "$SOURCE_FILE" && \
|
||||
# Sync file. Here, we use cp, but you could use rsync or other commands depending on your needs
|
||||
rsync -avu --delete "$SOURCE_FILE" "$TARGET_FILE"
|
||||
done
|
||||
```
|
||||
|
||||
|
||||
**bidirectional**
|
||||
inotify itself wont detect changes and even if we write 2 different statements then it will wait for first one to complete so we need to create 2 different sh files and execute those files in background
|
||||
|
||||
`sync_directories1.sh`
|
||||
```bash
|
||||
SOURCE=$1
|
||||
DESTINATION=$2
|
||||
|
||||
db_name= "main.kdbx"
|
||||
|
||||
SOURCE_FILE="$SOURCE/${db_name}"
|
||||
DESTINATION_FILE= "$DESTINATION/${db_name}"
|
||||
|
||||
# Function to sync directories
|
||||
sync_directories() {
|
||||
rsync -avu --ignore-existing "$SOURCE/${db_name}" "$DESTINATION/${db_name}"
|
||||
}
|
||||
|
||||
|
||||
# Ensure initial sync
|
||||
sync_directories
|
||||
|
||||
|
||||
# Monitor the source directory for any activity, and sync upon changes
|
||||
inotifywait -mre close_write,create,delete,move "$SOURCE" |
|
||||
while read -r directory events filename; do
|
||||
sync_directories
|
||||
done
|
||||
```
|
||||
`sync_directories2.sh`
|
||||
```bash
|
||||
SOURCE=$1
|
||||
DESTINATION=$2
|
||||
|
||||
db_name= "main.kdbx"
|
||||
|
||||
SOURCE_FILE="$SOURCE/${db_name}"
|
||||
DESTINATION_FILE= "$DESTINATION/${db_name}"
|
||||
|
||||
# Function to sync directories
|
||||
sync_directories2() {
|
||||
rsync --ignore-existing "$DESTINATION/${db_name}" "$SOURCE/${db_name}"
|
||||
}
|
||||
|
||||
# Ensure initial sync
|
||||
sync_directories2
|
||||
|
||||
inotifywait -mre close_write,create,delete,move "$DESTINATION" |
|
||||
while read -r directory events filename; do
|
||||
sync_directories2
|
||||
done
|
||||
|
||||
```
|
||||
`sync_directories.sh`
|
||||
```bash
|
||||
./sync_directories1.sh /path/to/first /path/to/second &
|
||||
./sync_directories2.sh /path/to/first /path/to/second &
|
||||
|
||||
```
|
||||
Finally execute `sync_directories.sh`
|
||||
Warning : using & means there will be problem in closing it
|
||||
- nohup to run script in backround without needing to keep terminal open
|
||||
if not available then install this with whole toolkit ie `coreutils`
|
||||
`nohup script.sh &`
|
||||
this will cause problems if we have to close processes
|
||||
- screen : multiplexer which will emulates terminal in background instead of process itself so easy to terminate processes.
|
||||
https://sentrytwo.com/6bb78a2539
|
||||
|
||||
to start the process in detached mode
|
||||
```bash
|
||||
screen -dmS sync1 ./sync_directories1.sh
|
||||
```
|
||||
this will start the session with name sync1
|
||||
|
||||
to close the session
|
||||
`screen -S sync1 -X quit`
|
||||
|
||||
|
||||
|
||||
- cron jobs
|
||||
- in arch by default cron service isnt installed so install it by
|
||||
`pacman -S cronie`
|
||||
https://phoenixnap.com/kb/set-up-cron-job-linux
|
||||
- Start cron service by
|
||||
`sudo systemctl start cron.service`
|
||||
in arch
|
||||
`sudo systemctl start cronie.service`
|
||||
- add cron tab through
|
||||
`crontab -e` then type
|
||||
`* * * * * /home/hpes/Videos/imp/scripts/crons/cronscript.sh`
|
||||
cron jub will run every minute
|
||||
Syntax is
|
||||
`<minute> <hour> <day_of_the_month> <month_of_the_year> <day_of_the_week> /path/to/your_script.sh`
|
||||
crontab location is `/var/spool/cron/`
|
||||
- Managing history in linux
|
||||
https://www.cyberciti.biz/faq/disable-bash-shell-history-linux/
|
||||
- check what service is connected to port (say 8080)
|
||||
`lsof -i :8080 -S`
|
||||
or
|
||||
`netstat -a | grep 8080`
|
||||
- text to speech
|
||||
using espeak
|
||||
`espeak 'wake up' 2>/dev/null`
|
||||
to get list of voices
|
||||
`espeak voices`
|
||||
to set the voice
|
||||
`espeak -v <voice>`
|
||||
|
||||
- umount target is busy
|
||||
`sudo umount -l /mnt/pendrive/` `-l` is important
|
||||
this is still dangerous though bcz it can unmount even the partition of the current os
|
||||
|
||||
https://stackoverflow.com/questions/7878707/how-to-unmount-a-busy-device
|
||||
- list drivers
|
||||
https://discuss.kde.org/t/settings-says-no-touchpad-found/14139
|
||||
`libinput list-devices`
|
||||
- hard reboot and hard shutdown
|
||||
Terminal command for hard-shutdown,
|
||||
`sudo sh -c "echo o > /proc/sysrq-trigger"`
|
||||
Terminal command for hard-restart,
|
||||
`sudo sh -c "echo b > /proc/sysrq-trigger"`
|
||||
- aliases
|
||||

|
||||

|
||||
- direnv
|
||||
to load and unload environment variables depending on current directory
|
||||
https://direnv.net/
|
||||
- date
|
||||
```
|
||||
You can refer to the following table to generate timestamps in various formats:
|
||||
Format / result Command Output
|
||||
YYYY-MM-DD date -I $(date -I)
|
||||
YYYY-MM-DD_hh:mm:ss date +%F_%T $(date +%F_%T)
|
||||
YYYYMMDD_hhmmss date +%Y%m%d_%H%M%S $(date +%Y%m%d_%H%M%S)
|
||||
YYYYMMDD_hhmmss (UTC version) date --utc +%Y%m%d_%H%M%SZ $(date --utc +%Y%m%d_%H%M%SZ)
|
||||
YYYYMMDD_hhmmss (with local TZ) date +%Y%m%d_%H%M%S%Z $(date +%Y%m%d_%H%M%S%Z)
|
||||
YYYYMMSShhmmss date +%Y%m%d%H%M%S $(date +%Y%m%d%H%M%S)
|
||||
YYYYMMSShhmmssnnnnnnnnn date +%Y%m%d%H%M%S%N $(date +%Y%m%d%H%M%S%N)
|
||||
YYMMDD_hhmmss date +%y%m%d_%H%M%S $(date +%y%m%d_%H%M%S)
|
||||
Seconds since UNIX epoch date +%s $(date +%s)
|
||||
Nanoseconds only date +%N $(date +%N)
|
||||
Nanoseconds since UNIX epoch date +%s%N $(date +%s%N)
|
||||
ISO8601 UTC timestamp date --utc +%FT%TZ $(date --utc +%FT%TZ)
|
||||
ISO8601 UTC timestamp + ms date --utc +%FT%T.%3NZ $(date --utc +%FT%T.%3NZ)
|
||||
ISO8601 Local TZ timestamp date +%FT%T%Z $(date +%FT%T%Z)
|
||||
YYYY-MM-DD (Short day) date +%F\(%a\) $(date +%F\(%a\))
|
||||
YYYY-MM-DD (Long day) date +%F\(%A\) $(date +%F\(%A\))
|
||||
```
|
||||
- finding duplicates
|
||||
for current dir
|
||||
```bash
|
||||
find -not -empty -type f -printf "%s
|
||||
" | sort -rn | uniq -d | xargs -I{} -n1 find -type f -size {}c -print0 | xargs -0 md5sum | sort | uniq -w32 --all-repeated=separate
|
||||
|
||||
```
|
||||
for custom one
|
||||
```bash
|
||||
find "$DIR" -not -empty -type f -printf "%s\n" |
|
||||
sort -rn |
|
||||
uniq -d |
|
||||
xargs -I{} -n1 find "$DIR" -type f -size {}c -print0 |
|
||||
xargs -0 md5sum |
|
||||
sort |
|
||||
uniq -w32 --all-repeated=separate
|
||||
```
|
||||
- fzf usage
|
||||
`find * -type f | fzf --multi > selected1`
|
||||
select files with shift+tab and then press enter and all the path will be saved to selected1 file
|
||||
- pretty print json
|
||||
`jq . package.json`
|
||||
here `.` is for current directory as top level directory is needed here
|
||||
and for reading large json do this
|
||||
`jq '.' large_file.json | less`
|
||||
- change default browser
|
||||
`xdg-settings set default-web-browser <insert the filename>.desktop`
|
||||
- get hashes
|
||||
`sha256sum <file>`. so there are others too: `sha1sum`, `md5sum`
|
||||
SHA-2 Family:
|
||||
The sha1sum tool, which uses SHA-1, is part of the broader SHA (Secure Hash Algorithm) family. Other members of this family include:
|
||||
sha256sum (256-bit hash, more secure than SHA-1)
|
||||
sha224sum (224-bit hash)
|
||||
sha384sum (384-bit hash)
|
||||
sha512sum (512-bit hash, offers maximum security in the SHA family)
|
||||
Blake2 : b2sum
|
||||
SHA-3 : `openssl sha3-256 file.txt`
|
||||
[sha types.txt](../../_resources/sha%20types.txt)
|
||||
- aur alternatuve in other distros
|
||||
Most distributions have larger repositories so don't need an AUR. Though, if you really want to dive into third-party repositories, I mean, there is Pacstall for Debian, Copr for Fedora, PPAs for Ubuntu, the community build system for openSUSE, the SlackBuilds for Slackware.
|
||||
|
||||
Plus Nix and pkgsrc are cross-distro and massive.
|
||||
|
||||
Basically no one else needs the AUR because there are lots of other, sometimes more extensive, options.
|
||||
- generate totp from totp key
|
||||
I have emailed myself the recovery codes and the actual totp key, I also have a bash alias
|
||||
```bash
|
||||
# for hex key
|
||||
alias GHGEN="oathtool --totp 'totp key here'"
|
||||
|
||||
# or for base32 key use
|
||||
alias GHGEN="oathtool -b --totp 'totp key here'"
|
||||
```
|
||||
https://gitlab.com/oath-toolkit/oath-toolkit
|
||||
-
|
||||
|
||||
|
||||
|
||||
Create a desktop entry of appimage with bash script
|
||||
|
||||
```sh
|
||||
#!/bin/bash
|
||||
|
||||
# Check if an AppImage file is passed as a parameter
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <AppImage file>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Assign the AppImage file path
|
||||
APPIMAGE_FILE="$1"
|
||||
|
||||
# Check if the provided AppImage file exists
|
||||
if [ ! -f "$APPIMAGE_FILE" ]; then
|
||||
echo "Error: File '$APPIMAGE_FILE' not found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract the application name (assuming the AppImage filename is the application name)
|
||||
APP_NAME=$(basename "$APPIMAGE_FILE" .AppImage)
|
||||
|
||||
# Create the desktop entry content
|
||||
DESKTOP_ENTRY="[Desktop Entry]
|
||||
Name=$APP_NAME
|
||||
Exec=$APPIMAGE_FILE
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Icon=$APPIMAGE_FILE
|
||||
Categories=Utility"
|
||||
|
||||
# Create the desktop entry filename
|
||||
DESKTOP_ENTRY_PATH="$HOME/.local/share/applications/$APP_NAME.desktop"
|
||||
|
||||
# Create the desktop entry file
|
||||
echo "$DESKTOP_ENTRY" > "$DESKTOP_ENTRY_PATH"
|
||||
|
||||
# Make the desktop entry executable
|
||||
chmod +x "$DESKTOP_ENTRY_PATH"
|
||||
|
||||
echo "Desktop entry for '$APP_NAME' created successfully at '$DESKTOP_ENTRY_PATH'"
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
xargs
|
||||
```sh
|
||||
rg --files | rg '.*\.json' | xargs stat
|
||||
|
||||
```
|
||||
|
||||
so whatever the output `rg --files | rg '.*\.json'` these will give stat will take as paameter lien by line so basicially `stat first line of output` and so on.
|
||||
|
||||
|
||||
|
||||
**xclip**
|
||||
clipboard for x11
|
||||
```sh
|
||||
# to clipboard
|
||||
xclip -selection clipboard -t image/png -i example.png
|
||||
# or
|
||||
# from clipboard
|
||||
xclip -o -se c -t image/png
|
||||
|
||||
# text to variable
|
||||
fullfilepath=$(xclip -selection clipboard -o)
|
||||
|
||||
```
|
||||
|
||||
images to file from clipboard
|
||||
x11
|
||||
`xclip -selection clipboard -t image/png -o > output.png`
|
||||
and for wayland
|
||||
install `wl-clipboard`
|
||||
and
|
||||
`wl-paste > output.png`
|
||||
|
||||
for file to clipboard
|
||||
`wl-copy -t image/png < /path/to/your/image.png`
|
||||
|
||||
|
||||
|
||||
**native games in linux**
|
||||
for native games in linux following 32 but libraries needed to be installed
|
||||
|
||||
`apt install libgl1:i386 libglx0:i386 libc6:i386 libstdc++6:i386`
|
||||
|
||||
|
||||
fix buzzing of sound
|
||||
- https://youtu.be/Kt0dkXWnaC4 : How To Fix Buzzing Speakers On Linux
|
||||
|
||||
|
||||
**Alternative of shred**
|
||||
|
||||
```sh
|
||||
dd if=/dev/urandom of=/storage/emulated/0/yourfile.txt bs=1M count=1
|
||||
rm /storage/emulated/0/yourfile.txt
|
||||
```
|
||||
|
||||
|
||||
openvpn setup as server
|
||||
|
||||
1. Run a popular, pre-made installation script for quick setup:
|
||||
`wget https://git.io/vpn -O openvpn-install.sh && bash openvpn-install.sh`.
|
||||
Follow the prompts on screen to set up protocols (UDP recommended), port (1194), and DNS.
|
||||
|
||||
2. Configure and Connect Client
|
||||
Once installed, the script will generate a .ovpn file (e.g., client.ovpn).
|
||||
Download this file from your VPS to your local computer/phone using SCP or SFTP.
|
||||
Install the OpenVPN Connect client app, import the .ovpn file, and click "Connect".
|
||||
3. in linux use `sudo openvpn --config client1.ovpn` to connect with it
|
||||
|
||||
|
||||
|
||||
### wireguard
|
||||
```sh
|
||||
curl -O https://raw.githubusercontent.com/angristan/wireguard-install/master/wireguard-install.sh
|
||||
chmod +x wireguard-install.sh
|
||||
./wireguard-install.sh
|
||||
```
|
||||
to check status
|
||||
`systemctl status wg-quick@wg0`
|
||||
|
||||
for bringiing down individual clients from server use
|
||||
|
||||
**to get list**
|
||||
`sudo wg show`
|
||||
|
||||
**for temporarily disable**
|
||||
`sudo wg set wg0 peer CLIENT_PUBLIC_KEY remove`
|
||||
or for safer just changed allowed ip
|
||||
`10.66.66.3/32, fd42:42:42::3/128` this was original lets say
|
||||
so use
|
||||
`sudo wg set wg0 peer CLIENT_PUBLIC_KEY allowed-ips 0.0.0.0/32`
|
||||
then later change back to
|
||||
`sudo wg set wg0 peer CLIENT_PUBLIC_KEY allowed-ips 10.66.66.3/32,fd42:42:42::3/128`
|
||||
|
||||
|
||||
**for permanent disable**
|
||||
`sudo nano /etc/wireguard/wg0.conf`
|
||||
|
||||
remove or comment out client
|
||||
```txt
|
||||
PublicKey = CLIENT_PUBLIC_KEY
|
||||
AllowedIPs = 10.0.0.3/32
|
||||
```
|
||||
|
||||
then apply changes
|
||||
```sh
|
||||
sudo wg-quick down wg0
|
||||
sudo wg-quick up wg0
|
||||
```
|
||||
|
||||
|
||||
other config details
|
||||
```txt
|
||||
|
||||
IPv4 or IPv6 public address: 198.12.73.213
|
||||
Public interface: eth0
|
||||
WireGuard interface name: wg0
|
||||
Server WireGuard IPv4: 10.66.66.1
|
||||
Server WireGuard IPv6: fd42:42:42::1
|
||||
Server WireGuard port [1-65535]: 53586
|
||||
First DNS resolver to use for the clients: 1.1.1.1
|
||||
Second DNS resolver to use for the clients (optional): 1.0.0.1
|
||||
|
||||
WireGuard uses a parameter called AllowedIPs to determine what is routed over the VPN.
|
||||
Allowed IPs list for generated clients (leave default to route everything): 0.0.0.0/0,::/0
|
||||
|
||||
```
|
||||
|
||||
in client
|
||||
**best method is to use wireguard**
|
||||
1. download wiregard profiles from https://account.protonvpn.com/downloads
|
||||
2. install wireguard-tools and then copy that conf files to /etc/wireguard
|
||||
3. run `sudo wg-quick up <conf_name>` (without .conf at end)
|
||||
4. to disconnect sudo wg-quick down <conf_name>
|
||||
Note : in proton config files, it is configured such that browsers cant access it so make changes in conf files like this
|
||||
AllowedIPs = 0.0.0.0/0, ::/0 to allow all network traffic
|
||||
5. for kill switch add above `peer` section
|
||||
```txt
|
||||
# Kill switch: block all traffic not going through WireGuard
|
||||
PostUp = iptables -I OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT && ip6tables -I OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
|
||||
PreDown = iptables -D OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT && ip6tables -D OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
|
||||
```
|
||||
|
||||
galv peer
|
||||
```txt
|
||||
peer: n4S+ao5+VqQRwYcYoHIslRKCgyyMAvUWlSuIOhztlC4=
|
||||
preshared key: (hidden)
|
||||
allowed ips: 10.66.66.4/32, fd42:42:42::4/128
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
nmap : nice command to get details of entered domain. scan networks for live hosts, open ports, running services, operating systems, and potential vulnerabilities
|
||||
|
||||
|
||||
`flatpak info --show-location io.gitlab.news_flash.NewsFlash`
|
||||
and for user data
|
||||
`~/.var/app`
|
||||
|
||||
to uninstall unsed packages
|
||||
`flatpak uninstall --unused`
|
||||
|
||||
to list themes
|
||||
`flatpak list --runtime | grep -i theme`
|
||||
|
||||
- check what process is precenting system from sleep
|
||||
`dbus-send --print-reply --dest=org.gnome.SessionManager /org/gnome/SessionManager org.gnome.SessionManager.GetInhibitors`
|
||||
then whatever the inhibtor id is returned use this
|
||||
` dbus-send --print-reply --dest=org.gnome.SessionManager /org/gnome/SessionManager/Inhibitor503 org.gnome.SessionManager.Inhibitor.GetAppId`
|
||||

|
||||
|
||||
|
||||
**isolate softwares**
|
||||
- using firejail
|
||||
`--private` : will disable access from filesystem
|
||||
`firejail --private firefox "http://dangerous-url.com"`
|
||||
for breaking off internet
|
||||
`firejail --net=none --private firefox "https://www.google.com"`
|
||||
|
||||
|
||||
|
||||
**get resource usage like cpu and ram of all processes containing the given keyword**
|
||||
useful to actually track things properly
|
||||
|
||||
for the physical memory
|
||||
`ps axo %cpu,rss,comm | awk '{print $1 "%\t" $2/1024 " MB\t" $3}'`: Lists CPU percentage, calculates memory in MB (RSS / 1024), and shows the command name.
|
||||
|
||||
when printing and using the 1st method it will just print one word so change comm to args and for real full thing use following
|
||||
`ps axo %cpu,rss,args | awk 'NR==1 {print "CPU%\tMEM_MB\tCOMMAND"; next} {printf "%s%%\t%.2f MB\t", $1, $2/1024; for(i=3;i<=NF;i++) printf "%s ", $i; print ""}'`
|
||||
|
||||
for swap one
|
||||
|
||||
```bash
|
||||
for pid in /proc/[0-9]*; do
|
||||
pid_num=$(basename $pid)
|
||||
swap=$(awk '/^Swap:/ {sum+=$2} END {print sum}' $pid/smaps_rollup 2>/dev/null)
|
||||
if [ ! -z "$swap" ] && [ "$swap" -gt 0 ]; then
|
||||
name=$(cat $pid/comm 2>/dev/null)
|
||||
echo "$swap $pid_num $name"
|
||||
fi
|
||||
done | sort -rn | head -n 10 | awk '{printf "PID: %-6s Swap: %.2f MB Command: %s\n", $2, $1/1024, $3}'
|
||||
|
||||
```
|
||||
for printing full command line
|
||||
```bash
|
||||
for pid in /proc/[0-9]*; do
|
||||
pid_num=$(basename $pid)
|
||||
swap=$(awk '/^Swap:/ {sum+=$2} END {print sum}' $pid/smaps_rollup 2>/dev/null)
|
||||
if [ ! -z "$swap" ] && [ "$swap" -gt 0 ]; then
|
||||
# Reads the full command line string and cleans up null characters
|
||||
full_cmd=$(tr '\0' ' ' < $pid/cmdline 2>/dev/null)
|
||||
# Fallback to short name if cmdline is empty (common for kernel threads)
|
||||
if [ -z "$full_cmd" ]; then full_cmd=$(cat $pid/comm 2>/dev/null); fi
|
||||
echo "$swap|$pid_num|$full_cmd"
|
||||
fi
|
||||
done | sort -t'|' -k1 -rn | head -n 10 | awk -F'|' '{printf "PID: %-6s Swap: %.2f MB Command: %s\n", $2, $1/1024, $3}'
|
||||
|
||||
```
|
||||
and finally a go program which can do this all
|
||||
[main.go](../../_resources/main.go)
|
||||
build it by
|
||||
`go build -o procusage main.go` and then `./procusage firefox`
|
||||
and the bash version
|
||||
[main1.sh](../../_resources/main1.sh)
|
||||
just use `bash main1.sh firefox` to run
|
||||
|
||||
go code listing all processes if no arguments are given and also tabular form
|
||||
[main.go](../../_resources/main-1.go)
|
||||
|
||||
|
||||
**change swapiness**
|
||||
|
||||
to check first
|
||||
`cat /proc/sys/vm/swappiness`
|
||||
|
||||
permanent solution
|
||||
`sudo nano /etc/sysctl.conf` and add
|
||||
`vm.swappiness=10` at bottom.
|
||||
do this to apply change without rebooting: `sudo sysctl -p`
|
||||
|
||||
temporary
|
||||
`sudo sysctl vm.swappiness=10`
|
||||
|
||||
|
||||
|
||||
android logs (crash logs including)
|
||||
|
||||
|
||||
```sh
|
||||
adb logcat
|
||||
|
||||
# for only errors
|
||||
adb logcat *:E
|
||||
```
|
||||
|
||||
for specific app
|
||||
```sh
|
||||
adb logcat | grep com.yourcompany.appname
|
||||
```
|
||||
3
joplin notion extension/linux/Extras/alpine.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
alpine
|
||||
|
||||
- installing i3 on alpine : https://wiki.alpinelinux.org/wiki/I3wm
|
||||
59
joplin notion extension/linux/Extras/amber bash.md
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
amber bash
|
||||
|
||||
https://docs.amber-lang.com/getting_started/getting_started
|
||||
|
||||
**installation**
|
||||
download its release and add binary to PATH env variable
|
||||
|
||||
**usage**
|
||||
`amber run main.ab` to simply run it
|
||||
|
||||
`amber build main.ab main.sh` to convert it into bash script
|
||||
`./main.sh`
|
||||
|
||||
**example**
|
||||
|
||||
```js
|
||||
// importing inbuilt methods for array and text variables
|
||||
import { split, slice } from "std/text"
|
||||
|
||||
const reduceFactor = 10
|
||||
|
||||
// this main function allows using arguments
|
||||
main(args){
|
||||
|
||||
echo(args[1])
|
||||
|
||||
// accepting first argument as folder. index 0 is just main.ab or bash
|
||||
const folder = args[1]
|
||||
|
||||
|
||||
// using commands and getting its output into text variable named 'res'
|
||||
let filesSortedByTimeStr = $ ls -t "{folder}" $ failed {echo(-1)}
|
||||
|
||||
// converting string to array with demiliter
|
||||
let filesSortedByTimeArray = split(filesSortedByTimeStr, "\n")
|
||||
|
||||
let abFilesSortedByTimeArray = []
|
||||
for index,file in filesSortedByTimeArray{
|
||||
|
||||
if slice(file, -4) == ".fos" {
|
||||
// add elements into array
|
||||
abFilesSortedByTimeArray+=[file]
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const bufferFolder = "{folder}/tobedeleted"
|
||||
$ mkdir -p "{bufferFolder}" $ failed {echo("couldnt created tobedeleted folder")}
|
||||
for index,file in abFilesSortedByTimeArray{
|
||||
if index % reduceFactor != 0{
|
||||
$ mv "{folder}/{file}" "{bufferFolder}/" $ failed {}
|
||||
}
|
||||
}
|
||||
|
||||
let res = abFilesSortedByTimeArray
|
||||
$ echo {res} > output.txt $ failed{}
|
||||
}
|
||||
|
||||
```
|
||||
18
joplin notion extension/linux/Extras/ssh.md
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
ssh
|
||||
|
||||
For connecting to remote device
|
||||
`ssh user@<host>` then type password if no ssh keys setup
|
||||
|
||||
non interactively with password
|
||||
1. install sshpaas https://github.com/kevinburke/sshpass
|
||||
for deb [sshpass_1.10-0.1_amd64.deb](../../../_resources/sshpass_1.10-0.1_amd64.deb)
|
||||
2. use this command
|
||||
`sshpass -p 'mypassword' scp myblogs.7z root@192.168.1.4:/root/projects/static/`
|
||||
more secure way
|
||||
```sh
|
||||
export SSHPASS='mypassword'
|
||||
sshpass -e scp myblogs.7z root@ 198.12.73.213:/root/projects/static/
|
||||
unset SSHPASS
|
||||
```
|
||||
3. for running commands non interactive
|
||||
`ssh user@host "command"`
|
||||
28
joplin notion extension/linux/Extras/vps.md
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
vps
|
||||
|
||||
|
||||
podman start commands
|
||||
|
||||
to keep it running
|
||||
podman run -itd -p 80:80 -p 443:443 --name vps1 vps-image:v1 /bin/bash
|
||||
|
||||
now later to open running container
|
||||
podman exec -it vps1 bash
|
||||
|
||||
btop
|
||||
btop --utf-force
|
||||
|
||||
2. java
|
||||
java -jar demo-0.0.1-SNAPSHOT.jar
|
||||
|
||||
3. npm
|
||||
pm2 start ecosystem.config.js --no-daemon
|
||||
|
||||
4.npm
|
||||
npm run start
|
||||
|
||||
5. npm
|
||||
npm run start
|
||||
|
||||
6. python
|
||||
python3 -m http.server 9020
|
||||
13
joplin notion extension/linux/Extras/yazi.md
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
yazi
|
||||
|
||||
- copy file path, go to this mode by pressing c.
|
||||
- to go to help press type `~` or f1 key
|
||||
- to sort go to sort mode by `,`.
|
||||
- to open options type `O`.
|
||||
- to go to a specfic directory use `g` and then space key
|
||||
- use `m` to show details like in detailed view
|
||||
|
||||
|
||||
|
||||
tip
|
||||
when opening tmux use this `tmux -u` to support icons
|
||||
4
joplin notion extension/linux/Gaming.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
Gaming
|
||||
|
||||
- https://usebottles.com/
|
||||
- https://steamdb.info/charts/?category=999
|
||||
14
joplin notion extension/linux/Grub Rescue error.md
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
### Grub Rescue error
|
||||
|
||||
- 
|
||||
- So from the pendrive which was used to install at first place, use this again and when powering on go to uefi boot option and select usb
|
||||
- Instead of usual one go to recovery or safe. it maybe under advanced
|
||||
- 
|
||||
- Select erase disk and install ubuntu bcz bootloader is corrupt
|
||||
- 
|
||||
Click on 'try again', not on 'continue anyway'
|
||||
|
||||
https://grubrescuesol.duckdocs.site/docs/first-page
|
||||
|
||||
|
||||
|
||||
9
joplin notion extension/linux/Pros.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
Pros
|
||||
|
||||
- Why better than apple?
|
||||
1. its true that like linux, apple is unix too but there one difference is that apple is proprietary and has so many restrictions while linux is open source and we can tinker it as we like
|
||||
2. in apple u may be able to learn something at surface level but when u face any errors u cant really do much about as it will harder to debug as i said apple is locked so u really cant get as much logs
|
||||
for example u r learning c or java or nodejs. u r facing problem in installation or using modules so there are some things which are tied at OS level . in that case u cant do nothing and in linux its true there are something manual but u get to learn a lot
|
||||
3. Do u know whats the best thing about open source. its the open standard which are common and acceptable in community so for your issues solutions will definitely gonna work unlike in windows and apple who regularly change their standards creating problem for end users.
|
||||
4. Now u may be thing open source also updates a lot . true but as its open source so u can choose what fits for u. Point is u have so many options and stability and what u learn will be useful for rest of your like unless window,apple who dont allow actual access and have to depend on their sdk and api
|
||||
5. NGL I was windows user for lot of time but it's constant upgrade really pissed me off. So I had installed linux and started using it but it was not my primary and was to use like sometimes in a week. When my ssd corrupted, I had to deal with hdd. Windows shit itself but I just installed light weight distro and it's performance is amazing for HDD.
|
||||
156
joplin notion extension/linux/Snippets/Bidirectional sync.md
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
Bidirectional sync
|
||||
https://sentrytwo.com/6bb78a2539
|
||||
|
||||
sync_directories1.sh
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
# SOURCE="/home/hpes/Videos/impnew/notes/keepaas_offline"
|
||||
# DESTINATION=" /home/hpes/Dropbox_keepaas/Apps/Keepaas2Android"
|
||||
|
||||
SOURCE=$1
|
||||
DESTINATION=$2
|
||||
|
||||
db_name= "main.kdbx"
|
||||
|
||||
SOURCE_FILE="$SOURCE/${db_name}"
|
||||
DESTINATION_FILE= "$DESTINATION/${db_name}"
|
||||
|
||||
# Function to sync directories
|
||||
sync_directories() {
|
||||
# rsync -avu --ignore-existing "$SOURCE/${db_name}" "$DESTINATION/${db_name}"
|
||||
rsync -avu "$SOURCE/${db_name}" "$DESTINATION/${db_name}"
|
||||
}
|
||||
|
||||
|
||||
# Ensure initial sync
|
||||
sync_directories
|
||||
|
||||
|
||||
|
||||
# Monitor the source directory for any activity, and sync upon changes
|
||||
inotifywait -mre close_write,create,delete,move "$SOURCE" |
|
||||
while read -r directory events filename; do
|
||||
sync_directories
|
||||
done
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
sync_directories.sh
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
|
||||
# SOURCE="/home/hpes/Videos/impnew/notes/keepaas_offline"
|
||||
# DESTINATION=" /home/hpes/Dropbox_keepaas/Apps/Keepaas2Android"
|
||||
|
||||
SOURCE=$1
|
||||
DESTINATION=$2
|
||||
|
||||
db_name= "main.kdbx"
|
||||
|
||||
SOURCE_FILE="$SOURCE/${db_name}"
|
||||
DESTINATION_FILE= "$DESTINATION/${db_name}"
|
||||
|
||||
# Function to sync directories
|
||||
sync_directories2() {
|
||||
rsync -avu "$DESTINATION/${db_name}" "$SOURCE/${db_name}"
|
||||
}
|
||||
|
||||
# Ensure initial sync
|
||||
sync_directories2
|
||||
|
||||
|
||||
|
||||
# Monitor the source directory for any activity, and sync upon changes
|
||||
inotifywait -mre close_write,create,delete,move "$SOURCE" |
|
||||
while read -r directory events filename; do
|
||||
sync_directories2
|
||||
done
|
||||
|
||||
|
||||
|
||||
```
|
||||
sync1.sh
|
||||
```bash
|
||||
/home/hpes/Videos/imp/scripts/sync_directories/sync_directories1.sh /home/hpes/Videos/impnew/notes/keepaas_offline /home/hpes/Dropbox_keepaas/Apps/Keepaas2Android
|
||||
|
||||
```
|
||||
|
||||
sync2.sh
|
||||
```bash
|
||||
/home/hpes/Videos/imp/scripts/sync_directories/sync_directories2.sh /home/hpes/Videos/impnew/notes/keepaas_offline /home/hpes/Dropbox_keepaas/Apps/Keepaas2Android
|
||||
|
||||
```
|
||||
|
||||
|
||||
sync_bi.sh
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
SCREEN_NAME1="sync1"
|
||||
SCREEN_NAME1_SCRIPT_PATH="/home/hpes/Videos/imp/scripts/sync_directories/sync1.sh"
|
||||
SCREEN_NAME2="sync2"
|
||||
SCREEN_NAME2_SCRIPT_PATH="/home/hpes/Videos/imp/scripts/sync_directories/sync2.sh"
|
||||
|
||||
start_script() {
|
||||
# Check if the screen session already exists
|
||||
if screen -list | grep -q "$SCREEN_NAME1"; then
|
||||
echo "Session already exists. Please stop it first or choose another name."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Start the screen session detached mode
|
||||
screen -dmS $SCREEN_NAME1 "$SCREEN_NAME1_SCRIPT_PATH"
|
||||
screen -dmS $SCREEN_NAME2 "$SCREEN_NAME2_SCRIPT_PATH"
|
||||
|
||||
echo "Script started in background under screen session '$SCREEN_NAME1' and '$SCREEN_NAME2'."
|
||||
}
|
||||
|
||||
stop_script() {
|
||||
# Kill the screen session
|
||||
screen -S $SCREEN_NAME1 -X quit
|
||||
screen -S $SCREEN_NAME2 -X quit
|
||||
echo "Screen session '$SCREEN_NAME1' and '$SCREEN_NAME2' stopped."
|
||||
}
|
||||
|
||||
# Check argument passed
|
||||
if [ "$#" -ne 1 ]; then
|
||||
echo "Usage: $0 {start|stop}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start_script
|
||||
;;
|
||||
stop)
|
||||
stop_script
|
||||
;;
|
||||
*)
|
||||
echo "Invalid option: $1"
|
||||
echo "Usage: $0 {start|stop}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# screen -dmS sync1 ./sync1.sh
|
||||
# screen -dmS sync2 ./sync2.sh
|
||||
|
||||
|
||||
```
|
||||
|
||||
Finally in `.bashrc` add
|
||||
```bash
|
||||
# creating alias for starting sync
|
||||
alias startsync="/home/hpes/Videos/imp/scripts/sync_directories/screen/sync_bi.sh start"
|
||||
|
||||
# run command for starting sync
|
||||
startsync
|
||||
|
||||
# creating alias for stopping sync
|
||||
alias closesync="/home/hpes/Videos/imp/scripts/sync_directories/screen/sync_bi.sh stop"
|
||||
```
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
deleting every 10th file
|
||||
|
||||
```sh
|
||||
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Directory containing save files (defaults to current directory)
|
||||
DIR="${1:-.}"
|
||||
|
||||
# Set to 1 to actually delete files; otherwise, preview only
|
||||
DELETE=0
|
||||
|
||||
mapfile -t files < <(
|
||||
find "$DIR" -maxdepth 1 -type f \
|
||||
-name 'ManualSave_*.sav' \
|
||||
-printf '%T@ %p\n' |
|
||||
sort -n |
|
||||
cut -d' ' -f2-
|
||||
)
|
||||
|
||||
total=${#files[@]}
|
||||
|
||||
echo "Found $total save files."
|
||||
echo "Keeping every 10th file, ordered oldest to newest."
|
||||
echo
|
||||
|
||||
for ((i = 0; i < total; i++)); do
|
||||
if (( (i + 1) % 10 == 0 )); then
|
||||
echo "KEEP ${files[i]}"
|
||||
else
|
||||
if (( DELETE )); then
|
||||
rm -- "${files[i]}"
|
||||
echo "DELETE ${files[i]}"
|
||||
else
|
||||
echo "WOULD DELETE ${files[i]}"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo
|
||||
if (( DELETE )); then
|
||||
echo "Done."
|
||||
else
|
||||
echo "Dry run only. No files were deleted."
|
||||
echo "To enable deletion, change DELETE=0 to DELETE=1."
|
||||
fi
|
||||
|
||||
```
|
||||
|
|
@ -0,0 +1,243 @@
|
|||
export file metadata and view it in nice frontend
|
||||
|
||||
**from llm**
|
||||
|
||||
It sounds like you're looking to create a **file explorer with metadata** and **tree view** functionality. Here's a general approach on how you can achieve this, even if you don't have direct access to the files themselves:
|
||||
|
||||
### Steps to Create a File Explorer with Metadata and Tree View
|
||||
|
||||
1. **Get the Directory Structure:**
|
||||
You can use a **recursive function** to traverse the directory and collect information about files and folders in a hierarchical structure (like a tree view). The key is to capture all relevant metadata along with each file and folder.
|
||||
|
||||
2. **Collect Metadata:**
|
||||
For each file and folder, you can collect the following metadata:
|
||||
|
||||
* **File name**
|
||||
* **File size**
|
||||
* **File type/extension**
|
||||
* **Creation date**
|
||||
* **Last modified date**
|
||||
* **Permissions** (Read/Write/Execute)
|
||||
* **Owner (if available)**
|
||||
|
||||
3. **Export the Data:**
|
||||
Once you've gathered all this information, you can export it to a structured format such as **JSON** or **CSV**. JSON would be ideal for this, as it can represent hierarchical data.
|
||||
|
||||
4. **Display with Tree View:**
|
||||
You can then build a tree view UI using HTML, JavaScript, and CSS (e.g., using frameworks like **React** or **Vue.js**). Each item in the tree can be toggled open or closed to reveal the metadata for files and folders.
|
||||
|
||||
### Code Example (Python Script to Export Metadata)
|
||||
|
||||
Here’s a Python script that will scan a directory and gather the metadata:
|
||||
|
||||
```python
|
||||
import os
|
||||
import json
|
||||
from datetime import datetime
|
||||
|
||||
def get_file_metadata(file_path):
|
||||
stats = os.stat(file_path)
|
||||
return {
|
||||
"name": os.path.basename(file_path),
|
||||
"size": stats.st_size,
|
||||
"creation_date": datetime.fromtimestamp(stats.st_ctime).strftime('%Y-%m-%d %H:%M:%S'),
|
||||
"modified_date": datetime.fromtimestamp(stats.st_mtime).strftime('%Y-%m-%d %H:%M:%S'),
|
||||
"permissions": oct(stats.st_mode)[-3:],
|
||||
"is_directory": os.path.isdir(file_path)
|
||||
}
|
||||
|
||||
def build_tree(directory):
|
||||
directory_tree = []
|
||||
for root, dirs, files in os.walk(directory):
|
||||
root_metadata = get_file_metadata(root)
|
||||
tree_item = {
|
||||
"path": root,
|
||||
"metadata": root_metadata,
|
||||
"files": [],
|
||||
"subfolders": []
|
||||
}
|
||||
|
||||
# Get files in the current folder
|
||||
for file in files:
|
||||
file_path = os.path.join(root, file)
|
||||
file_metadata = get_file_metadata(file_path)
|
||||
tree_item["files"].append(file_metadata)
|
||||
|
||||
# Get subfolders (recursive)
|
||||
for dir in dirs:
|
||||
dir_path = os.path.join(root, dir)
|
||||
dir_metadata = get_file_metadata(dir_path)
|
||||
tree_item["subfolders"].append(build_tree(dir_path)[0]) # Recursively add subfolders
|
||||
|
||||
directory_tree.append(tree_item)
|
||||
return directory_tree
|
||||
|
||||
def save_to_json(data, filename="directory_structure.json"):
|
||||
with open(filename, "w") as f:
|
||||
json.dump(data, f, indent=4)
|
||||
|
||||
# Example usage
|
||||
directory = "/path/to/your/directory" # Change this to your directory
|
||||
tree_data = build_tree(directory)
|
||||
save_to_json(tree_data)
|
||||
```
|
||||
|
||||
### Explanation:
|
||||
|
||||
1. **`get_file_metadata`**: This function collects metadata for a file or folder (like creation and modification dates, size, permissions, etc.).
|
||||
2. **`build_tree`**: This function uses `os.walk()` to traverse the directory and construct a tree with file metadata and subdirectories.
|
||||
3. **`save_to_json`**: This function saves the gathered data in a JSON file.
|
||||
|
||||
or bash script can be used too
|
||||
|
||||
```sh
|
||||
#!/bin/bash
|
||||
|
||||
# Usage: ./dir_tree.sh /path/to/directory > output.json
|
||||
|
||||
DIR=${1:-.}
|
||||
|
||||
echo "["
|
||||
|
||||
first=1
|
||||
find "$DIR" -print0 | while IFS= read -r -d '' file; do
|
||||
[ $first -eq 0 ] && echo ","
|
||||
first=0
|
||||
|
||||
name=$(basename "$file")
|
||||
size=$(stat -c %s "$file")
|
||||
created=$(stat -c %w "$file") # May be '-' on some systems
|
||||
modified=$(stat -c %y "$file")
|
||||
perms=$(stat -c %a "$file")
|
||||
is_dir=false
|
||||
[ -d "$file" ] && is_dir=true
|
||||
|
||||
# Output as JSON object
|
||||
echo " {"
|
||||
echo " \"path\": \"${file//\"/\\\"}\","
|
||||
echo " \"name\": \"${name//\"/\\\"}\","
|
||||
echo " \"size\": $size,"
|
||||
echo " \"creation_date\": \"${created//\"/\\\"}\","
|
||||
echo " \"modified_date\": \"${modified//\"/\\\"}\","
|
||||
echo " \"permissions\": \"$perms\","
|
||||
echo " \"is_directory\": $is_dir"
|
||||
echo -n " }"
|
||||
done
|
||||
|
||||
echo
|
||||
echo "]"
|
||||
tar
|
||||
```
|
||||
|
||||
### Frontend: Displaying the Tree View
|
||||
|
||||
You can use **HTML, CSS, and JavaScript** to display the file structure and metadata in a tree view. If you're familiar with **React**, it's even easier.
|
||||
|
||||
Here’s an example of how you can structure the tree view with HTML:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>File Explorer</title>
|
||||
<style>
|
||||
.folder { font-weight: bold; cursor: pointer; }
|
||||
.file { font-style: italic; }
|
||||
.metadata { margin-left: 20px; }
|
||||
.hidden { display: none; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="tree-view"></div>
|
||||
|
||||
<script>
|
||||
// Sample JSON data (replace with your actual JSON from the Python script)
|
||||
const treeData = [
|
||||
{
|
||||
"path": "/path/to/folder",
|
||||
"metadata": {
|
||||
"name": "folder",
|
||||
"size": 1234,
|
||||
"creation_date": "2025-05-08 14:30:00",
|
||||
"modified_date": "2025-05-08 14:45:00",
|
||||
"permissions": "755",
|
||||
"is_directory": true
|
||||
},
|
||||
"files": [
|
||||
{
|
||||
"name": "file1.txt",
|
||||
"size": 200,
|
||||
"creation_date": "2025-05-08 14:30:00",
|
||||
"modified_date": "2025-05-08 14:40:00",
|
||||
"permissions": "644",
|
||||
"is_directory": false
|
||||
}
|
||||
],
|
||||
"subfolders": []
|
||||
}
|
||||
];
|
||||
|
||||
function createTreeView(data, parentElement) {
|
||||
data.forEach(item => {
|
||||
const folderDiv = document.createElement("div");
|
||||
folderDiv.classList.add("folder");
|
||||
folderDiv.textContent = item.metadata.name;
|
||||
folderDiv.onclick = () => toggleFolder(folderDiv, item);
|
||||
|
||||
const metadataDiv = document.createElement("div");
|
||||
metadataDiv.classList.add("metadata", "hidden");
|
||||
metadataDiv.innerHTML = `
|
||||
<p>Size: ${item.metadata.size} bytes</p>
|
||||
<p>Created: ${item.metadata.creation_date}</p>
|
||||
<p>Modified: ${item.metadata.modified_date}</p>
|
||||
<p>Permissions: ${item.metadata.permissions}</p>
|
||||
`;
|
||||
|
||||
folderDiv.appendChild(metadataDiv);
|
||||
parentElement.appendChild(folderDiv);
|
||||
|
||||
// Recursively add files and subfolders
|
||||
if (item.files.length > 0 || item.subfolders.length > 0) {
|
||||
const subFolderDiv = document.createElement("div");
|
||||
subFolderDiv.classList.add("subfolder");
|
||||
|
||||
item.files.forEach(file => {
|
||||
const fileDiv = document.createElement("div");
|
||||
fileDiv.classList.add("file");
|
||||
fileDiv.textContent = file.name;
|
||||
subFolderDiv.appendChild(fileDiv);
|
||||
});
|
||||
|
||||
item.subfolders.forEach(subfolder => {
|
||||
createTreeView([subfolder], subFolderDiv);
|
||||
});
|
||||
|
||||
folderDiv.appendChild(subFolderDiv);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function toggleFolder(folderDiv, item) {
|
||||
const metadataDiv = folderDiv.querySelector(".metadata");
|
||||
metadataDiv.classList.toggle("hidden");
|
||||
}
|
||||
|
||||
createTreeView(treeData, document.getElementById("tree-view"));
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### Steps to Implement:
|
||||
|
||||
1. **Data Fetching:** You will need to load your **JSON** file (from the Python script) into the front-end application. This can be done using a simple `fetch()` call or by directly embedding the JSON data.
|
||||
2. **Displaying Metadata:** Each folder and file item can display its name and, when clicked, show the metadata (size, creation date, etc.).
|
||||
3. **Tree View Toggle:** The metadata will be hidden by default and only visible when the folder is toggled.
|
||||
|
||||
### Conclusion:
|
||||
|
||||
By following this method, you can gather all file and folder metadata, export it as JSON, and then visualize the data in a **tree structure** with toggling effects on the front end. This would allow you to review file and folder properties without direct access to the actual files.
|
||||
61
joplin notion extension/linux/Snippets/sed example.md
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
sed example
|
||||
|
||||
|
||||
theory
|
||||
grep is powerful along with other unix tools like cut xargs head less etc.
|
||||
awk goes line by line in a file/stdin giving you all the words in variables with like $1 $2 $3 which you can use however you want
|
||||
|
||||
To achieve this using `sed` (Stream Editor), you can use a regular expression pattern to match the text you want to modify and then replace it with the desired output.
|
||||
|
||||
Assuming you want to remove the `.md` from occurrences of patterns like `(sdusyd.md)` within a file and considering your example, we use the following `sed` command:
|
||||
|
||||
```bash
|
||||
sed 's/\(([^)]*)\).md/\1/g' file.txt
|
||||
```
|
||||
|
||||
Here's a breakdown of the command:
|
||||
|
||||
- `sed`: The command to call Stream Editor.
|
||||
- `s/pattern/replacement/`: The substitute command, where `pattern` is the regex pattern you are looking to match, and `replacement` is the text you want to use to replace the matched pattern.
|
||||
- `\(([^)]*)\).md`: This is the regex pattern we are matching.
|
||||
- `\(`: Matches the literal character "(".
|
||||
- `([^)]*)`: Matches and captures any character except `)` zero or more times. This corresponds to your `<string>`.
|
||||
- `\)`: Matches the literal character ")".
|
||||
- `.md`: Matches the string `.md` that we intend to remove.
|
||||
- `\1`: Refers to the first captured group from the match. In this case, it's the string matched by `([^)]*)`, which is `<string>`.
|
||||
- `g`: Global flag to perform the replacement for all occurrences within a line.
|
||||
- `file.txt`: The file in which the replacements should occur.
|
||||
|
||||
|
||||
For example, if `file.txt` contains:
|
||||
|
||||
```text
|
||||
Some text (sdusyd.md) with markdown files and another (anotherfile.md).
|
||||
```
|
||||
|
||||
After running the command, it will output:
|
||||
|
||||
```text
|
||||
Some text (sdusyd) with markdown files and another (anotherfile).
|
||||
```
|
||||
|
||||
**Note**: If you want to directly modify the file (instead of just outputting the modified text to the terminal), you can use the `-i` option for in-place editing with `sed`. Just remember to backup your original files before using `-i`, as it overwrites the original file:
|
||||
|
||||
```bash
|
||||
sed -i 's/\(([^)]*)\).md/\1/g' file.txt
|
||||
```
|
||||
|
||||
This will change `file.txt` in-place.
|
||||
|
||||
- same thing with perl
|
||||
`perl -pe 's/\(([^()]+)\.md\)/\($1\)/g' file.txt` : this will only print output without modifying file
|
||||
`perl -pi -e 's/\(([^()]+)\.md\)/\($1\)/g' test.txt` : this will modify file too
|
||||
|
||||
this worked for me
|
||||
```bash
|
||||
sed -E -i 's/\(([^\)]*)\.md\)/\(\1\)/g' file.txt
|
||||
```
|
||||
|
||||
|
||||
replicating grep with awk
|
||||
`history | awk '/cd/'` will replicate3 `history | grep 'cd'`
|
||||
8
joplin notion extension/linux/Softwares/distrobox.md
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
distrobox
|
||||
|
||||
- Create arch container using distrobox
|
||||
`distrobox-create archc --image docker.io/library/archlinux:latest`
|
||||
- To enter a container use
|
||||
`distrobox enter archc`
|
||||
- To stop the container use
|
||||
`distrobox stop archc`
|
||||
17
joplin notion extension/linux/Terminal instances.md
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
Terminal instances
|
||||
|
||||
- To launch terminal with command cmus and window title as cmus
|
||||
`xfce4-terminal --title="cmus" --command="cmus"`
|
||||
Now this can be saved in .sh file and then executed as desktop entry [Desktop Entry]
|
||||
|
||||
- For konsole terminal emulator
|
||||
`konsole --hold -e bash -c "sleep 1 && echo -ne '\033]30;cmus\007' && cmus"`
|
||||
|
||||
- For tmux
|
||||
```bash
|
||||
# Start a new tmux session named "my-cli-session"
|
||||
tmux new-session -d -s cmus "cmus"
|
||||
|
||||
# Run your CLI tool command in the new tmux session
|
||||
tmux send-keys -t cmus "cmus" Enter
|
||||
```
|
||||
6
joplin notion extension/linux/Theory.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
Theory
|
||||
|
||||
- mkinitcpio
|
||||
It is used to generate initrd (initial ramdisk). : The initial ramdisk is in essence a very small environment (early userspace) which loads various kernel modules and sets up necessary things before handing over control to init .
|
||||
|
||||
it is a scheme of loading temporary file system into memory as a part of linux startup process. Very useful in case system not starts and to edit or fix it it falls to initrd fallback
|
||||
0
joplin notion extension/linux/Untitled.md
Normal file
22
joplin notion extension/linux/XDM.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
- Installing xdm
|
||||
|
||||
[https://www.youtube.com/watch?v=cdMiAgQe3_I](https://www.youtube.com/watch?v=cdMiAgQe3_I)
|
||||
|
||||
|
||||
[xdm-browser-monitor-master.zip](../../_resources/xdm-browser-monitor-master.zip)
|
||||
|
||||
- here is the solutions
|
||||
|
||||
download https://github.com/subhra74/xdm-browser-monitor as a zip and extract it
|
||||
|
||||
then go to the chrome extension page and activate developper mode
|
||||
|
||||
then click load extension on the top left and select the chrome folder inside the extracted zip
|
||||
|
||||
after that just clear the error if there is and you are done
|
||||
|
||||
- Issues
|
||||
- Not able to append
|
||||
https://www.youtube.com/watch?v=wAkNiPCO6E0
|
||||
|
||||
34
joplin notion extension/linux/XFCE.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
XFCE
|
||||
|
||||
- window focus
|
||||
go to focus tab on window manager setting and uncheck options 'Automatically give focus to newly created windows'
|
||||
and
|
||||
Raise window when clicking inside application window
|
||||
|
||||
This will solve the problem of drag and drop when windows are overlapping each other
|
||||
|
||||
Xfce packages
|
||||
|
||||
There are 15 members in group xfce4:
|
||||
:: Repository extra
|
||||
1) exo 2) garcon 3) thunar 4) thunar-volman 5) tumbler
|
||||
6) xfce4-appfinder 7) xfce4-panel 8) xfce4-power-manager 9) xfce4-session
|
||||
10) xfce4-settings 11) xfce4-terminal 12) xfconf 13) xfdesktop 14) xfwm4
|
||||
15) xfwm4-themes
|
||||
|
||||
Enter a selection (default=all):
|
||||
:: There are 36 members in group xfce4-goodies:
|
||||
:: Repository extra
|
||||
1) mousepad 2) parole 3) ristretto 4) thunar-archive-plugin
|
||||
5) thunar-media-tags-plugin 6) xfburn 7) xfce4-artwork
|
||||
8) xfce4-battery-plugin 9) xfce4-clipman-plugin 10) xfce4-cpufreq-plugin
|
||||
11) xfce4-cpugraph-plugin 12) xfce4-dict 13) xfce4-diskperf-plugin
|
||||
14) xfce4-eyes-plugin 15) xfce4-fsguard-plugin 16) xfce4-genmon-plugin
|
||||
17) xfce4-mailwatch-plugin 18) xfce4-mount-plugin 19) xfce4-mpc-plugin
|
||||
20) xfce4-netload-plugin 21) xfce4-notes-plugin 22) xfce4-notifyd
|
||||
23) xfce4-pulseaudio-plugin 24) xfce4-screensaver 25) xfce4-screenshooter
|
||||
26) xfce4-sensors-plugin 27) xfce4-smartbookmark-plugin
|
||||
28) xfce4-systemload-plugin 29) xfce4-taskmanager
|
||||
30) xfce4-time-out-plugin 31) xfce4-timer-plugin 32) xfce4-verve-plugin
|
||||
33) xfce4-wavelan-plugin 34) xfce4-weather-plugin
|
||||
35) xfce4-whiskermenu-plugin 36) xfce4-xkb-plugin
|
||||
56
joplin notion extension/linux/cmus music player.md
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
cmus music player
|
||||
|
||||
`yay -S cmus`
|
||||
|
||||
https://linux.die.net/man/7/cmus-tutorial
|
||||
|
||||
```
|
||||
b player-next
|
||||
c player-pause
|
||||
x player-play
|
||||
z player-prev
|
||||
v player-stop
|
||||
|
||||
B player-next-album
|
||||
Z player-prev-album
|
||||
|
||||
] vol +0 +1%
|
||||
[ vol +1% +0
|
||||
+ vol +10%
|
||||
= vol +10%
|
||||
} vol -0 -1%
|
||||
{ vol -1% -0
|
||||
- vol -10%
|
||||
|
||||
, seek -1m
|
||||
. seek +1m
|
||||
|
||||
h seek -5
|
||||
l seek +5
|
||||
|
||||
left seek -5
|
||||
right seek +5
|
||||
|
||||
mlb_click_bar player-pause
|
||||
mouse_scroll_up_bar seek +5
|
||||
mouse_scroll_down_bar seek -5
|
||||
|
||||
```
|
||||
|
||||
some audio files may not get played bcz ffmpeg priority is low by default and other input audio plugin will take place which will produce a screeching voice so go to
|
||||
` ~/.config/cmus/autosave` and change the ffmpeg plugin pritority to highest like 60.
|
||||
|
||||
`set input.ffmpeg.priority=60`
|
||||
|
||||
Also u can change output plugin too
|
||||
`set output_plugin=alsa`
|
||||
to
|
||||
`set output_plugin=pulse`
|
||||
|
||||
- For adding resume feature when u close it down
|
||||
`set resume=true`
|
||||
|
||||
- after sorting the song , to play them like that,
|
||||
`set play_sorted=true`
|
||||
- update directory
|
||||
press `u` or `add <path_to_directory>`
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
vlc plugin for firefox
|
||||
|
||||
|
||||
```text
|
||||
/home/hpes/.nvm/versions/node/v14.0.0/bin/node
|
||||
NodeJS status = 0
|
||||
Installer is using your system NodeJS.
|
||||
|
||||
-> Root directory is /home/hpes/.config
|
||||
-> Creating a directory at /home/hpes/.config/google-chrome/NativeMessagingHosts
|
||||
-> Chrome Browser is supported
|
||||
-> Creating a directory at /home/hpes/.config/chromium/NativeMessagingHosts
|
||||
-> Chromium Browser is supported
|
||||
-> Creating a directory at /home/hpes/.config/vivaldi/NativeMessagingHosts
|
||||
-> Vivaldi Browser is supported
|
||||
-> Creating a directory at /home/hpes/.config/BraveSoftware/Brave-Browser/NativeMessagingHosts
|
||||
-> Brave Browser is supported
|
||||
-> Creating a directory at /home/hpes/.config/microsoftedge/NativeMessagingHosts
|
||||
-> Microsoft Edge Browser is supported
|
||||
-> Creating a directory at /home/hpes/.mozilla/native-messaging-hosts
|
||||
-> Firefox Browser is supported
|
||||
-> Creating a directory at /home/hpes/.waterfox/native-messaging-hosts
|
||||
-> Waterfox Browser is supported
|
||||
-> Creating a directory at /home/hpes/.tor-browser/app/Browser/TorBrowser/Data/Browser/.mozilla/native-messaging-hosts
|
||||
-> Tor Browser is supported
|
||||
-> Creating a directory at /home/hpes/.thunderbird/native-messaging-hosts
|
||||
-> Thunderbird Email Client is supported
|
||||
-> Creating a directory at /home/hpes/.config/com.add0n.node
|
||||
=> Native Host is installed in /home/hpes/.config/com.add0n.node
|
||||
|
||||
```
|
||||
12
joplin notion extension/linux/endeavour os/Basics.md
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
Basics
|
||||
|
||||
- In arch based never do `pacman -Sy`. always do `pacman -S` or `pacman -Sy` bcz if repos are partially updated then it will break things
|
||||
- list all packages with sizes sorted with size too
|
||||
`pacman -Qi | awk '/^Name/{name=$3}/^Installed Size/{size=$4; unit=$5; if(unit=="MiB") size*=1024; print name, size, unit}' | sort -k2,2nr | awk '{size=$2; unit=$3; if(size>=1048576) {printf "%-30s %.2f GiB\n", $1, size/1048576} else if(size>=1024) {printf "%-30s %.2f MiB\n", $1, size/1024} else {printf "%-30s %d KiB\n", $1, size}}'
|
||||
`
|
||||
mentioning packages with size with no sorting
|
||||
`pacman -Qi | awk '/^Name/{name=$3}/^Installed Size/{size=$4 " " $5; print name, size}'`
|
||||
- list orphan package
|
||||
`pacman -Qdt`
|
||||
to remove them run
|
||||
`pacman -Rns $(pacman -Qdtq)`
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
Extras endeavour
|
||||
|
||||
- Remove saving of state
|
||||
Default DE is KDE. Go to system settings->startup and shutdown->desktop session and choose 'Start with an empty session'
|
||||
- Select files with single click instead of opening it
|
||||
System settings -> WorkSpace Behavior -> General Behavior -> "Clicking files or folders"
|
||||
- konsole transparency
|
||||
In Konsole you have to go to Settings >> Edit Current Profile >> Appearance
|
||||
When you are in the Appearance tab, you only have to select a Color Scheme and Background and then clic on the edit button. There you can set the level of transparency you want.
|
||||
- Virtual desktop
|
||||
system Settings->WorkSpace behaviour->Virtual Desktops
|
||||
simplescreenrecorder-2024-02-13_13.04.56.mp4 https://small.fileditchstuff.me/s4/nlbjBNbfcqcLqclSEud.mp4
|
||||
To switch apps between workspace, remove pin at top left so that they switch to other desktop when we switch to other desktop too. and toggle pin on again if dont wanna move to other desktop
|
||||
kde_desktop app switch.mp4 https://small.fileditchstuff.me/s4/NvsLWPyqIuLywHtMCOiC.mp4
|
||||
|
||||
|
||||
[kde_desktop app switch.mp4](../../../_resources/kde_desktop%20app%20switch.mp4)
|
||||
Or workspace behavior,-> screen edges and enable "Switch desktop on edge"
|
||||
https://askubuntu.com/questions/90143/kde4-move-window-to-another-workspace-by-dragging
|
||||
- sort process in btop
|
||||
there is a cpu lazy just below cpu usage. it is thing sorting based on. change it using left and right arrow keys
|
||||
|
||||
- ignore signature when installing arch packages offline
|
||||
https://www.archlinuxuser.com/2012/06/ignore-signature-check-when-doing.html
|
||||
`nano /etc/pacman.conf`
|
||||
then
|
||||
```text
|
||||
# By default, pacman accepts packages signed by keys that its local keyring
|
||||
# trusts (see pacman-key and its man page), as well as unsigned packages.
|
||||
#SigLevel = Optional TrustedOnly
|
||||
```
|
||||
|
||||
change to
|
||||
```text
|
||||
# By default, pacman accepts packages signed by keys that its local keyring
|
||||
# trusts (see pacman-key and its man page), as well as unsigned packages.
|
||||
#SigLevel = Optional TrustedOnly
|
||||
SigLevel = Never
|
||||
```
|
||||
|
||||
- bluettoth
|
||||
To Check Bluetooth Status:
|
||||
On Windows:
|
||||
netsh interface show interface "Bluetooth Network Connection"
|
||||
On macOS:
|
||||
system_profiler SPBluetoothDataType | grep "Power"
|
||||
On Linux:
|
||||
`rfkill list bluetooth`
|
||||
|
||||
```text
|
||||
To Turn off Bluetooth:
|
||||
On Windows:
|
||||
|
||||
netsh interface set interface "Bluetooth Network Connection" admin=disable
|
||||
|
||||
On macOS: (Requires administrator privileges and may vary based on macOS version)
|
||||
|
||||
sudo defaults write /Library/Preferences/com.apple.Bluetooth ControllerPowerState -int 0
|
||||
sudo killall -HUP blued
|
||||
```
|
||||
On Linux:
|
||||
`rfkill block bluetooth`
|
||||
Turn on
|
||||
`rfkill unblock bluetooth`
|
||||
Using init system ie systemd
|
||||
`systemctl status bluetooth.service
|
||||
- delete indexed database for start menu in kde
|
||||
kde uses baloo for indexing files and deleted files may still be there bcz database may not have updated so need to manulally remove them.
|
||||
1. Disable Baloo File Indexer: First, you need to stop the Baloo service to prevent it from indexing while you're cleaning its database. You can do this by running the following command in the terminal:
|
||||
`balooctl suspend`
|
||||
2. Delete the Index Database: Next, you'll want to delete the existing index database. This can be done by removing the Baloo database files located in your ~/.local/share/baloo directory. Use the command:
|
||||
`rm -r ~/.local/share/baloo`
|
||||
|
||||
|
||||
3. Enable Baloo File Indexer: After deleting the database, you should enable the Baloo service again to start a fresh indexing process. Use the command:
|
||||
`balooctl resume`
|
||||
|
||||
4. Reindex Files: Finally, you may want to force the start of the reindexing process. You can do that with:
|
||||
`balooctl check`
|
||||
- to downgrade python version
|
||||
Download desired version from
|
||||
`https://archive.archlinux.org/packages/p/python`
|
||||
then install pkg.tar.zst with
|
||||
`sudo pacman -U python-3.11.3-1-x86_64.pkg.tar.zst`
|
||||
|
||||
also use this to fix some errors
|
||||
`yay -Sy $(pacman -Qq | grep python)` this will upgrade all python related
|
||||
|
||||
- remove icon cache
|
||||
```bash
|
||||
rm -rf ~/.cache/icon-cache.kcache
|
||||
rm -rf ~/.cache/plasma_icons*
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
36
joplin notion extension/linux/endeavour os/Issues.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
Issues
|
||||
|
||||
- webview glitch
|
||||
kde_webview_glitch.mp4 https://small.fileditchstuff.me/s4/EQfnXtDfhjMaeqyHPtfB.mp4
|
||||
- Sleep mode not working
|
||||
Run this command to check status
|
||||
`systemctl status systemd-suspend.service`
|
||||
and then enable it
|
||||
`systemctl enable systemd-suspend.service`
|
||||
- In onlyoffice there might be a problem that ui is so large so fix it use
|
||||
`/usr/bin/onlyoffice-desktopeditors --force-scale=1.3`
|
||||
Ref: https://www.reddit.com/r/OnlyOffice/comments/ur8ykg/does_version_710215_have_any_way_to_change/
|
||||
- kdewallet popup removal
|
||||
`~/.config/kwalletrc` and under `[wallet]` `enabled=false`
|
||||
or in kwalletmanager go to settings -> Configure wallet
|
||||
Uncheck "Enable the KDE wallet subsystem" and click OK.
|
||||
- kde gui glitches
|
||||
kde glitches recent update.mp4 https://files.catbox.moe/qhnwbq.mp4
|
||||
solution
|
||||
https://wiki.archlinux.org/title/Downgrading_packages
|
||||
- installing without using `yay -Sy` after few weeks
|
||||
just update mirrorlist and keyring
|
||||
https://archlinux.org/packages/core/any/archlinux-keyring/
|
||||
- sometimes there is mismatch in app id for filename of .desktop at `usr/share/applications` and what kde is trying to look for
|
||||
its simple really. click on titlebar, more -> special application settings -> down there, there is a "add property" button -> search for desktop file name and click on that, first click on "force temporarily" and set it to "sublime_text_3" (click apply then) and then set it to "remember" (and click apply)
|
||||
search "desktop file" in add property menu
|
||||

|
||||
|
||||
|
||||
|
||||
diagnosis
|
||||
|
||||
```
|
||||
kernel: usb 1-2.2: PM: dpm_run_callback(): usb_dev_resume+0x0/0x20 returns -5
|
||||
kernel: usb 1-2.2: PM: failed to resume async: error -5
|
||||
```
|
||||
76
joplin notion extension/linux/endeavour os/Scripts.md
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
Scripts
|
||||
|
||||
- for downloading packages from arch archive
|
||||
```sh
|
||||
#!/bin/bash
|
||||
|
||||
# Check if the input file is provided
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <file_with_package_names>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if the file exists
|
||||
if [ ! -f "$1" ]; then
|
||||
echo "File '$1' not found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Read the file line by line
|
||||
while IFS= read -r package; do
|
||||
# If the line is not empty
|
||||
if [ -n "$package" ]; then
|
||||
# Construct the URL based on the pattern
|
||||
url="https://archive.archlinux.org/packages/${package:0:1}/$package"
|
||||
|
||||
# Output the URL
|
||||
echo "Downloading: $url"
|
||||
|
||||
# Download the package using wget
|
||||
wget "$url"
|
||||
fi
|
||||
done < "$1"
|
||||
|
||||
```
|
||||
(this one is not working)
|
||||
Running it:
|
||||
`bash download_packages.sh packages.txt`
|
||||
Then to install these all
|
||||
`sudo pacman -U $(< packages.txt)`
|
||||
or
|
||||
`sudo pacman -U *.zst`
|
||||
|
||||
new one
|
||||
```sh
|
||||
#!/bin/bash
|
||||
|
||||
# Check if the input file is provided
|
||||
if [ -z "$1" ]; then
|
||||
echo "Usage: $0 <file_with_package_names>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if the file exists
|
||||
if [ ! -f "$1" ]; then
|
||||
echo "File '$1' not found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Read the file line by line
|
||||
while IFS= read -r package; do
|
||||
# If the line is not empty
|
||||
if [ -n "$package" ]; then
|
||||
# Extract the package name (e.g., "binaryen" from "binaryen-1:120-1-x86_64.pkg.tar.zst")
|
||||
package_name=$(echo "$package" | cut -d '-' -f 1)
|
||||
|
||||
# Construct the URL based on the pattern
|
||||
url="https://archive.archlinux.org/packages/${package_name:0:1}/$package_name/$package"
|
||||
|
||||
# Output the URL
|
||||
echo "Downloading: $url"
|
||||
|
||||
# Download the package using wget
|
||||
wget "$url"
|
||||
fi
|
||||
done < "$1"
|
||||
```
|
||||
4
joplin notion extension/linux/endeavour os/Widgets.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
Widgets
|
||||
|
||||
- Netspeed(sysfs) : network usage on taskbar
|
||||
- hard disk activityt: disk i/o on taskbar
|
||||
245
joplin notion extension/linux/linux gang useful snippets.md
Normal file
|
|
@ -0,0 +1,245 @@
|
|||
linux gang useful snippets
|
||||
|
||||
1. Create Discord Server Invite Using Bot And Channel ID
|
||||
|
||||
```jsx
|
||||
const { Client } = require('discord.js');
|
||||
const bot = new Client({ intents: 65 });
|
||||
|
||||
bot.on("ready", async () => {
|
||||
const channel = bot.channels.cache.get(CHANNEL_ID);
|
||||
if (channel) {
|
||||
const invite = await channel.createInvite();
|
||||
console.log(`Created an invite with the code: https://discord.gg/${invite.code}`);
|
||||
} else {
|
||||
console.error("Could not find the specified channel or guild.");
|
||||
}
|
||||
});
|
||||
|
||||
bot.login(BOT_TOKEN);
|
||||
```
|
||||
|
||||
2. reduce windows latency by a lot
|
||||
https://youtu.be/n9xAG3nb9XQ
|
||||
this is a video that explains it well and shows you how to do it
|
||||
https://files.catbox.moe/btx6iz.mp4
|
||||
3. Find any file on the filesystem with "whatever" in its name
|
||||
A lot of you probably already know this, and it isn't really a snippet, just a useful little command.
|
||||
You can use `find / -name "*whatever*"` to find any file with "whatever" in the name on the filesystem, obviously you can replace "whatever" with anything you wanna look for and "/" with any directory you wanna look in.
|
||||
4. Python html maker
|
||||
[Python html maker](../../undefined)
|
||||
5. wget using /dev/tcp
|
||||
|
||||
```bash
|
||||
wget ()
|
||||
{
|
||||
IFS=/ read proto z host query <<< "$1"
|
||||
exec 3< /dev/tcp/$host/80
|
||||
{
|
||||
echo GET /$query HTTP/1.1
|
||||
echo connection: close
|
||||
echo host: $host
|
||||
echo
|
||||
} >&3
|
||||
sed '1,/^$/d' <&3 > $(basename $1)
|
||||
}
|
||||
```
|
||||
|
||||
5. Get file length in C(bytes)
|
||||
|
||||
```c
|
||||
#include <stdio.h>
|
||||
|
||||
FILE* file;
|
||||
|
||||
int main()
|
||||
{
|
||||
file = fopen("/path/to/file", "rb");
|
||||
fseek(file, 0L, SEEK_END);
|
||||
long fileSize = ftell(file);
|
||||
fseek(file, 0L, SEEK_SET);
|
||||
|
||||
printf("The file is %i bytes long\n", fileSize);
|
||||
}
|
||||
```
|
||||
|
||||
[get file length in C](../../undefined)
|
||||
|
||||
6. Simple 'note' command
|
||||
`alias note='echo -e "$(date)" "$\n" "$1" >> ~/notes.txt'`
|
||||
or
|
||||
|
||||
```bash
|
||||
function note () {
|
||||
echo -e "$(date)" "$\n" "$1" >> ~/notes.txt;
|
||||
}
|
||||
note test
|
||||
note again
|
||||
cat ~/notes.txt
|
||||
```
|
||||
|
||||
7. Personal shell aliases
|
||||
|
||||
|
||||
```
|
||||
alias -g GONULL="> /dev/null"
|
||||
alias chfg="$EDITOR -- ~/.zshrc"
|
||||
alias sosh="source ~/.zshrc"
|
||||
|
||||
alias cat="bat --style=grid"
|
||||
# not inspired by pbcopy
|
||||
alias pc="xclip -i"
|
||||
alias pp="xclip -o"
|
||||
```
|
||||
|
||||
8. python board
|
||||
|
||||
```py
|
||||
from turtle import *
|
||||
import random
|
||||
|
||||
def buttonclick(x,y):
|
||||
print("{0}, {1}".format(x, y))
|
||||
onscreenclick(buttonclick,1)
|
||||
|
||||
class Cellules():
|
||||
def __init__(self, cellule_size=(62, 62), cellules=(10, 10), width=5, tspeed=0):
|
||||
self.cs = cellule_size
|
||||
self.width = width
|
||||
self.cellules = cellules
|
||||
self.speed = tspeed
|
||||
|
||||
def start(self):
|
||||
dr = Screen()
|
||||
#dr.mainloop()
|
||||
self.cellule = [[(int(self.cs[0]*i*-1), int(self.cs[1]*j)) for j in range(int(-1*(self.cellules[1])/2), int((self.cellules[1])/2))] for i in range(int(-1*self.cellules[0]/2), int(self.cellules[0]/2))]
|
||||
#self.cellule = self.cellule[1::]
|
||||
self.cellule = [i[::-1] for i in self.cellule[::-1]]
|
||||
print(self.cellule)
|
||||
dr.setup(width=1+self.cs[0]*self.cellules[0], height=1+self.cs[1]*self.cellules[1])
|
||||
width(5)
|
||||
speed(self.speed)
|
||||
|
||||
def fill(self, go, colour):
|
||||
penup()
|
||||
goto(self.cellule[go[0]][go[1]][0], self.cellule[go[0]][go[1]][1])
|
||||
pendown()
|
||||
print(self.cellule[go[0]][go[1]][0], self.cellule[go[0]][go[1]][1])
|
||||
begin_fill()
|
||||
color(colour)
|
||||
width, height = self.cs
|
||||
left(180)
|
||||
for i in range(2):
|
||||
forward(width)
|
||||
right(90)
|
||||
forward(height)
|
||||
right(90)
|
||||
end_fill()
|
||||
|
||||
def add(self, x, y):
|
||||
self.fill((x, y), "black")
|
||||
|
||||
def rm(self, x, y):
|
||||
self.fill((x, y), "white")
|
||||
|
||||
|
||||
#cellules = Cellules(cellules=(nombres_des_abscices, nombre_des_ordonnee), cellule_size=(la_largeur, la_longueur))
|
||||
cellules = Cellules(cellules=(50, 50), cellule_size=(12.4, 12.4))
|
||||
cellules.start()
|
||||
|
||||
#cellules.add(x, y)
|
||||
cellules.add(0, 0)
|
||||
|
||||
done()
|
||||
```
|
||||
|
||||
9.
|
||||
```bash
|
||||
# Print my public IP
|
||||
alias myip='curl ipinfo.io/ip'
|
||||
# or
|
||||
alias myip2='curl ipwho.de'
|
||||
```
|
||||
|
||||
10. Symbolic links
|
||||
https://linuxhint.com/create-symbolic-links-manjaro/
|
||||
`ln -s [path-of-target-file] [path-of-symlink-file]`
|
||||
`ln -s linuxhint.txt symfile.txt`
|
||||
|
||||
**For verification of symbolic link**
|
||||
`ls -l sym_dir`
|
||||
|
||||
**For full path sym links**
|
||||
You can turn relative paths into full paths using readlink -f foo. So you would do something like:
|
||||
`ln -s $(readlink -f $origlink) $newlink`
|
||||
|
||||
11. Caption any image (and optionally convert it to a gif)
|
||||
Requires:
|
||||
`xclip kalker imagemagick ffmpeg dmenu`
|
||||
|
||||
Kalker is in the AUR, everything else is in normal arch repos
|
||||
|
||||
Usage:
|
||||
`caption <url or file>`
|
||||
will let you add a caption and convert into either image or gif
|
||||
for videos and gifs, use only gif as your convert option
|
||||
|
||||
Also automatically puts images into clipboard; Gifs output to /tmp/cap.gif
|
||||
|
||||
Code:
|
||||
|
||||
```bash
|
||||
#!/bin/sh
|
||||
CAPTION=$(: | eval "dmenu -p \"Search\"")
|
||||
IMAGE=$1
|
||||
|
||||
image() {
|
||||
width=`identify -format %w $IMAGE`
|
||||
echo $width
|
||||
convert $IMAGE -size ${width}x -gravity Center -background white -fill black -pointsize $(echo $width/13 | kalker) -font Fira-Code-Bold caption:"$CAPTION" +swap -gravity Center -append /tmp/caption.png
|
||||
xclip -selection c -t image/png /tmp/caption.png
|
||||
rm /tmp/caption.png
|
||||
}
|
||||
|
||||
gif() {
|
||||
mkdir -p /tmp/caption
|
||||
ffmpeg -i $IMAGE /tmp/caption/cap%04d.png
|
||||
width=`identify -format %w /tmp/caption/cap0001.png`
|
||||
framerate=`ffmpeg -i $IMAGE 2>&1 | sed -n "s/.*, \(.*\) fp.*/\1/p"`
|
||||
for i in /tmp/caption/cap*.png; do
|
||||
echo $i
|
||||
convert $i -size ${width}x -gravity Center -background white -fill black -pointsize $(echo $width/13 | kalker) -font Fira-Code-Bold caption:"$CAPTION" +swap -gravity Center -append "$i.new.png"
|
||||
done;
|
||||
ffmpeg -y -i /tmp/caption/cap%04d.png.new.png -vf "fps=$framerate,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" -fs 8M /tmp/cap.gif
|
||||
xclip -selection c -t image/gif /tmp/cap.gif
|
||||
rm -r /tmp/caption
|
||||
# rm /tmp/cap.gif
|
||||
notify-send "complete"
|
||||
}
|
||||
|
||||
case $(printf "gif\nimage" | dmenu -i -p "is gif?") in
|
||||
gif) gif;;
|
||||
image) image ;;
|
||||
*) exit 1;;
|
||||
esac
|
||||
```
|
||||
|
||||
12. Just drag and drop the text file you need to fix on top of the executable, should overwrite it with the correct version
|
||||
Or you can call it from the command line like .\FixEncoding file1.txt file2.txt file3.txt etc....
|
||||
|
||||
using System.Text;
|
||||
|
||||
```bash
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
File.WriteAllText(args[i], Encoding.Default.GetString(Encoding.Convert(Encoding.Unicode, Encoding.UTF8, Encoding.Unicode.GetBytes(File.ReadAllText(args[i])))));
|
||||
```
|
||||
|
||||
13. check weather
|
||||

|
||||
`curl wttr.in`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
19
joplin notion extension/linux/linux gang.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
linux gang
|
||||
|
||||
- Cool resources
|
||||
1. https://mdxjs.com/ : Markdown for the
|
||||
component era | MDX
|
||||
MDX lets you use JSX in your markdown content. You can import components, such as interactive charts or alerts, and embed them within your content. This makes writing long-form content with components a blast.
|
||||
2. https://www.litespeedtech.com/products/litespeed-web-server : LiteSpeed Web Server is an Apache alternative that conserves resources without sacrificing performance, security, or convenience. Double the capacity of your current Apache servers! Securely handle thousands of concurrent clients while consuming minimal memory and CPU. Compatible with your favorite control panel.
|
||||
3. https://www.fxsound.com/ : Windows Only (ironic), Makes sound simply sound like 3x better on almost all my windows machines without any tweaking except from picking a profile
|
||||
4. https://rednoise.org/adntest/googleAdSenseCases.html
|
||||
Good for testing a adblocker
|
||||
If you use uBlock Origin you should have atleast 15 on its badge on this website
|
||||
5. Differences between HTTP 1.1, 2 and 3
|
||||

|
||||
6. https://free-mp3-download.net/
|
||||
Download lossless cd quality music for free
|
||||
7. GitHub - raoofha/gter: embed a GUI app inside a terminal window or ...
|
||||
embed a GUI app inside a terminal window or any other window - GitHub - raoofha/gter: embed a GUI app inside a terminal window or any other window
|
||||
8. https://scnlog.me/apps/gnulinux/ : cracked list of proprietary software for linux
|
||||
9. https://www.reddit.com/r/fullmoviesonyoutube/ : reddit thread containing link of youtube videos containing full movie
|
||||
180
joplin notion extension/linux/mint/applets.md
Normal file
|
|
@ -0,0 +1,180 @@
|
|||
applets
|
||||
|
||||
to create applet for linux mint cinnamon DE
|
||||
|
||||
# Applet for Linux Cinnamon to Display Download/Upload Speed
|
||||
|
||||
Here's a simple applet code for Linux Cinnamon that displays your current network download and upload speeds. This creates a panel applet similar to what you might see in Windows task manager or other system monitors.
|
||||
|
||||
## Prerequisites
|
||||
1. Linux Cinnamon desktop environment
|
||||
2. Python 3.x
|
||||
3. `gir1.2-gtk-3.0` and `gir1.2-appindicator3-0.1` packages (usually installed by default)
|
||||
|
||||
## Applet Code
|
||||
|
||||
Create a new directory for your applet and save these files:
|
||||
|
||||
### 1. `network-speed@yourname/files/network-speed@yourname/applet.js`
|
||||
|
||||
```javascript
|
||||
const Applet = imports.ui.applet;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const St = imports.gi.St;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Gettext = imports.gettext;
|
||||
|
||||
function MyApplet(metadata, orientation, panel_height, instance_id) {
|
||||
this._init(metadata, orientation, panel_height, instance_id);
|
||||
}
|
||||
|
||||
MyApplet.prototype = {
|
||||
__proto__: Applet.TextIconApplet.prototype,
|
||||
|
||||
_init: function(metadata, orientation, panel_height, instance_id) {
|
||||
Applet.TextIconApplet.prototype._init.call(this, orientation, panel_height, instance_id);
|
||||
|
||||
try {
|
||||
this.metadata = metadata;
|
||||
this.uuid = this.metadata.uuid;
|
||||
this.instance_id = instance_id;
|
||||
|
||||
this.setAllowedLayout(Applet.AllowedLayout.BOTH);
|
||||
|
||||
// Initial values
|
||||
this.downSpeed = 0;
|
||||
this.upSpeed = 0;
|
||||
this.prevDownBytes = 0;
|
||||
this.prevUpBytes = 0;
|
||||
|
||||
// Get initial network stats
|
||||
this.getNetworkStats();
|
||||
|
||||
// Update every second
|
||||
this.timeout = Mainloop.timeout_add_seconds(1, () => {
|
||||
this.getNetworkStats();
|
||||
return true;
|
||||
});
|
||||
|
||||
this.on_orientation_changed(orientation);
|
||||
|
||||
} catch (e) {
|
||||
global.logError(e);
|
||||
}
|
||||
},
|
||||
|
||||
getNetworkStats: function() {
|
||||
try {
|
||||
let [res, out, err, status] = GLib.spawn_command_line_sync('cat /proc/net/dev');
|
||||
if (status === 0) {
|
||||
let lines = out.toString().split('\n');
|
||||
let downBytes = 0;
|
||||
let upBytes = 0;
|
||||
|
||||
// Skip first 2 lines (header)
|
||||
for (let i = 2; i < lines.length; i++) {
|
||||
let line = lines[i].trim();
|
||||
if (line === '') continue;
|
||||
|
||||
let iface = line.split(':')[0].trim();
|
||||
// Skip lo (loopback) interface
|
||||
if (iface === 'lo') continue;
|
||||
|
||||
let stats = line.split(':')[1].trim().split(/\s+/);
|
||||
downBytes += parseInt(stats[0]);
|
||||
upBytes += parseInt(stats[8]);
|
||||
}
|
||||
|
||||
// Calculate speeds (bytes per second)
|
||||
if (this.prevDownBytes > 0 && this.prevUpBytes > 0) {
|
||||
this.downSpeed = downBytes - this.prevDownBytes;
|
||||
this.upSpeed = upBytes - this.prevUpBytes;
|
||||
}
|
||||
|
||||
this.prevDownBytes = downBytes;
|
||||
this.prevUpBytes = upBytes;
|
||||
|
||||
this.updateUI();
|
||||
}
|
||||
} catch (e) {
|
||||
global.logError(e);
|
||||
}
|
||||
},
|
||||
|
||||
updateUI: function() {
|
||||
try {
|
||||
let down = this.formatSpeed(this.downSpeed);
|
||||
let up = this.formatSpeed(this.upSpeed);
|
||||
this.set_applet_label(`↓${down} ↑${up}`);
|
||||
} catch (e) {
|
||||
global.logError(e);
|
||||
}
|
||||
},
|
||||
|
||||
formatSpeed: function(bytes) {
|
||||
if (bytes < 1024) {
|
||||
return bytes + 'B';
|
||||
} else if (bytes < 1024 * 1024) {
|
||||
return Math.round(bytes / 1024) + 'K';
|
||||
} else {
|
||||
return Math.round(bytes / (1024 * 1024)) + 'M';
|
||||
}
|
||||
},
|
||||
|
||||
on_orientation_changed: function(orientation) {
|
||||
this.orientation = orientation;
|
||||
},
|
||||
|
||||
on_applet_removed_from_panel: function() {
|
||||
if (this.timeout) {
|
||||
Mainloop.source_remove(this.timeout);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function main(metadata, orientation, panel_height, instance_id) {
|
||||
return new MyApplet(metadata, orientation, panel_height, instance_id);
|
||||
}
|
||||
```
|
||||
|
||||
### 2. `network-speed@yourname/files/network-speed@yourname/metadata.json`
|
||||
|
||||
```json
|
||||
{
|
||||
"uuid": "network-speed@yourname",
|
||||
"name": "Network Speed Monitor",
|
||||
"description": "Displays current download and upload speeds",
|
||||
"icon": "network-wired",
|
||||
"max-instances": 1
|
||||
}
|
||||
```
|
||||
|
||||
### 3. `network-speed@yourname/files/network-speed@yourname/stylesheet.css`
|
||||
|
||||
```css
|
||||
.network-speed-applet {
|
||||
padding: 2px;
|
||||
}
|
||||
```
|
||||
|
||||
## Installation
|
||||
|
||||
1. Create the directory structure:
|
||||
```bash
|
||||
mkdir -p ~/.local/share/cinnamon/applets/network-speed@yourname
|
||||
```
|
||||
|
||||
2. Copy the three files above to this directory.
|
||||
|
||||
3. Restart Cinnamon (press Alt+F2, type "r" and press Enter).
|
||||
|
||||
4. Right-click on the panel, choose "Applets", find "Network Speed Monitor" and add it to your panel.
|
||||
|
||||
## Customization Options
|
||||
|
||||
1. You can change the update interval by modifying the timeout value in `applet.js`.
|
||||
2. To change the display format, modify the `formatSpeed` function.
|
||||
3. You can add tooltips or more detailed information by expanding the code.
|
||||
|
||||
This applet reads from `/proc/net/dev` to get network statistics, which is the most reliable method on Linux. It shows download (↓) and upload (↑) speeds in a compact format (B for bytes, K for kilobytes, M for megabytes per second).
|
||||
8
joplin notion extension/linux/mint/basics.md
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
basics
|
||||
|
||||
to automatically install all prompts use
|
||||
`sudo apt install librewolf -y`
|
||||
- to install packages offline in debian use this
|
||||
`sudo dpkg -i windscribe_2.14.12_amd64.deb`
|
||||
if facing error in borken/missing dependencies use this and then start offline way again
|
||||
`sudo apt install -f`
|
||||
22
joplin notion extension/linux/mint/extras.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
extras
|
||||
|
||||
**to install nerd fonts**
|
||||
1. go to this site https://www.nerdfonts.com/font-downloads and download zip package
|
||||
2. in `.local/share/fonts` (create fonts if not already there) copy the extracted version and then restart the terminal and fonts will be loaded
|
||||
|
||||
- old debian pacages resides in universe repo
|
||||
https://old-releases.ubuntu.com/ubuntu/pool/universe/s/sshpass/
|
||||
|
||||
|
||||
|
||||
for gpu temperature check
|
||||
`sensors` and for gpu other process `radeontop`
|
||||
|
||||
|
||||
to know ubuntu/debian releases
|
||||
`echo $(lsb_release -cs)`
|
||||
|
||||
|
||||
|
||||
to know about which ubuntu release in detail
|
||||
`tail -n 3 /etc/os-release`
|
||||
263
joplin notion extension/linux/mint/i3 wm.md
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
i3 wm
|
||||
|
||||
todo
|
||||
lock screen change
|
||||
dark mode
|
||||
sleep mode
|
||||
|
||||
dmenu : win+D
|
||||
to include desktop shortcut
|
||||
1. `nano ~/.config/i3/config`
|
||||
2. Find the keybinding for your application launcher (usually bindsym $mod+d).
|
||||
3. Change `dmenu_run` to `i3-dmenu-desktop`:
|
||||
`bindsym $mod+d exec --no-startup-id i3-dmenu-desktop`
|
||||
or for with icons and better use
|
||||
`bindsym $mod+d exec --no-startup-id rofi -show drun -show-icons`
|
||||
(make sure to install rofi)
|
||||
5. Reload i3 with $mod+Shift+c or $mod+Shift+r to apply the changes
|
||||
|
||||
|
||||
tabbed mode : win + w
|
||||
split mode : win + e
|
||||
stack mode : win + s3
|
||||
|
||||
log out and log in of sway (to apply effects) : win+shift+r
|
||||
logout : mod+shift+e
|
||||
|
||||
themes and something else (llm generated)
|
||||
[dark theme i3.md](../../../_resources/dark%20theme%20i3.md)
|
||||
1st step fixed flatpak and some other theme (xdg protal one)
|
||||
2nd step fixed xfce apps (gtk settings one321)
|
||||
or this can be installed too for gui changes
|
||||
`sudo apt install lxappearance gtk-chtheme qt4-qtconfig`
|
||||
|
||||
qt4qtconfig is outdated so use `qt5ct` to make changes
|
||||
|
||||
in `/etc/environment` have this `echo $QT_QPA_PLATFORMTHEME=qt5ct:qt6ct` and reboot
|
||||
also install these
|
||||
`sudo apt install breeze qt6-gtk-platformtheme qt6ct qt5ct`
|
||||
|
||||
now in toolbar set the theme like breeze dark
|
||||
|
||||
for flatpak
|
||||
`flatpak --user override --env=GTK_THEME=Adwaita:dark`
|
||||
|
||||
and to unset it
|
||||
`flatpak --user override --unset-env=GTK_THEME`
|
||||
|
||||
and for gtk4 and libwaita this will help for dark theme
|
||||
`ADW_DEBUG_COLOR_SCHEME=prefer-dark`
|
||||
|
||||
|
||||
theme that are availables in mine
|
||||
```txt
|
||||
Adwaita Mint-L-Aqua Mint-L-Dark-Brown Mint-L-Darker-Orange Mint-L-Dark-Grey Mint-L-Dark-Teal Mint-L-Sand Mint-X-compact Mint-X-Sand Mint-Y-Dark-Aqua Mint-Y-Dark-Red Mint-Y-Purple
|
||||
Adwaita-dark Mint-L-Blue Mint-L-Darker Mint-L-Darker-Pink Mint-L-Dark-Orange Mint-L-Grey Mint-L-Teal Mint-X-Grey Mint-X-Teal Mint-Y-Dark-Blue Mint-Y-Dark-Sand Mint-Y-Red
|
||||
Default Mint-L-Brown Mint-L-Darker-Aqua Mint-L-Darker-Purple Mint-L-Dark-Pink Mint-L-Orange Mint-X Mint-X-Orange Mint-Y Mint-Y-Dark-Grey Mint-Y-Dark-Teal Mint-Y-Sand
|
||||
Emacs Mint-L-Dark Mint-L-Darker-Blue Mint-L-Darker-Red Mint-L-Dark-Purple Mint-L-Pink Mint-X-Aqua Mint-X-Pink Mint-Y-Aqua Mint-Y-Dark-Orange Mint-Y-Grey Mint-Y-Teal
|
||||
HighContrast Mint-L-Dark-Aqua Mint-L-Darker-Brown Mint-L-Darker-Sand Mint-L-Dark-Red Mint-L-Purple Mint-X-Blue Mint-X-Purple Mint-Y-Blue Mint-Y-Dark-Pink Mint-Y-Orange Raleigh
|
||||
Mint-L Mint-L-Dark-Blue Mint-L-Darker-Grey Mint-L-Darker-Teal Mint-L-Dark-Sand Mint-L-Red Mint-X-Brown Mint-X-Red Mint-Y-Dark Mint-Y-Dark-Purple Mint-Y-Pink
|
||||
|
||||
```
|
||||
|
||||
|
||||
### lock, suspend
|
||||
instead of using one like cinnamon login manager, it will use something like i3lock
|
||||
https://github.com/betterlockscreen/betterlockscreen
|
||||
|
||||
`wget https://raw.githubusercontent.com/betterlockscreen/betterlockscreen/main/install.sh -O - -q | bash -s user
|
||||
`
|
||||
and then
|
||||
store `~/.local/.bin` in PATH
|
||||
and
|
||||
|
||||
`sudo apt install imagemagick`
|
||||
|
||||
|
||||
also install this
|
||||
`https://github.com/Raymo111/i3lock-color`
|
||||
|
||||
in i3 config file
|
||||
`exec no-startup-id xautolock -time 15 -locker "systemctl suspend"`
|
||||
use exec_always if u want changes to take place after reload instead of just reloading configs via mod+shift+r.
|
||||
`exec_always --no-startup-id xautolock -time 15 -locker "systemctl suspend"`
|
||||
for wakelock to prevent sleep , this alias
|
||||
```sh
|
||||
alias nosl="systemd-inhibit --what=sleep --who="bot" --why="discord bot running" sleep infinity"
|
||||
```
|
||||
|
||||
about waking up after suspend
|
||||
|
||||
```sh
|
||||
# Shows the hardware-level wake reason (e.g. "PCI PME#", "Power Switch", "RTC")
|
||||
sudo dmidecode | grep Wake-up
|
||||
|
||||
|
||||
# Check which IRQ caused the last wake
|
||||
cat /sys/power/pm_wakeup_irq
|
||||
```
|
||||
|
||||
kernel sources
|
||||
|
||||
```sh
|
||||
# Shows all wakeup sources with event counts
|
||||
cat /sys/kernel/debug/wakeup_sources
|
||||
|
||||
# and for more
|
||||
|
||||
# List all wakeup-capable devices
|
||||
ls /sys/class/wakeup/
|
||||
|
||||
# Check event counts (compare before/after suspend to find the culprit)
|
||||
for i in /sys/class/wakeup/wakeup*; do
|
||||
echo "$i: $(cat $i/event_count)"
|
||||
done
|
||||
```
|
||||
|
||||
**better status bar**
|
||||
install i3blocks
|
||||
```sh
|
||||
sudo apt install i3blocks
|
||||
cp /etc/i3blocks.conf ~/.config/i3/i3blocks.conf
|
||||
```
|
||||
then replacing i3status with i3blocks:
|
||||
```txt
|
||||
bar {
|
||||
status_command i3blocks
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### brightness and volume keybinds
|
||||
`sudo apt install brightnessctl`
|
||||
|
||||
to prevent brightnessctl to require sudo, do this
|
||||
`sudo usermod -aG video $USER`
|
||||
|
||||
then in config
|
||||
```txt
|
||||
bindsym XF86MonBrightnessUp exec --no-startup-id brightnessctl set +5%
|
||||
bindsym XF86MonBrightnessDown exec --no-startup-id brightnessctl set 5%-
|
||||
|
||||
```
|
||||
|
||||
for volume as it is changed to i3blocks do this. basically this first line is important so change that
|
||||
```txt
|
||||
set $refresh_i3status pkill -SIGRTMIN+10 i3blocks
|
||||
bindsym XF86AudioRaiseVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ +10% && $refresh_i3status
|
||||
bindsym XF86AudioLowerVolume exec --no-startup-id pactl set-sink-volume @DEFAULT_SINK@ -10% && $refresh_i3status
|
||||
bindsym XF86AudioMute exec --no-startup-id pactl set-sink-mute @DEFAULT_SINK@ toggle && $refresh_i3status
|
||||
bindsym XF86AudioMicMute exec --no-startup-id pactl set-source-mute @DEFAULT_SOURCE@ toggle && $refresh_i3status
|
||||
```
|
||||
|
||||
and also
|
||||
`cinnamon-settings sound` to open cinnamon inbuilt sound control or `pavucontrol` for another one
|
||||
|
||||
natural scroling
|
||||
add this in i3 config
|
||||
|
||||
this touchpad device can be listed by finding from `xinput list`
|
||||
```txt
|
||||
exec_always --no-startup-id xinput set-prop "ELAN0708:00 04F3:30A0 Touchpad" "libinput Natural Scrolling Enabled" 1
|
||||
```
|
||||
|
||||
for pasting content from clipboard to markdown
|
||||
in config
|
||||
```sh
|
||||
bindsym $mod+shift+p exec --no-startup-id bash /home/hpmi/Videos/imp/scripts/attachment-clipboard.sh "normal"
|
||||
bindsym $mod+shift+Mod1+p exec --no-startup-id bash /home/hpmi/Videos/imp/scripts/attachment-clipboard.sh "alt"
|
||||
```
|
||||
|
||||
and the script used
|
||||
```sh
|
||||
pasteToArea(){
|
||||
MY_VAR="$1"
|
||||
|
||||
# 1. Copy the variable to the clipboard
|
||||
echo -n "$MY_VAR" | xclip -selection clipboard
|
||||
|
||||
# 2. Force xdotool to wait until you release the physical hotkey,
|
||||
# then clear modifiers and paste. This prevents key conflicts.
|
||||
|
||||
sleep 1
|
||||
xdotool key --clearmodifiers ctrl+v
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
DESTINATION="$HOME/.gram-md/_assets"
|
||||
|
||||
|
||||
# normal or alt
|
||||
mode=$1
|
||||
echo $mode
|
||||
if xclip -selection clipboard -t TARGETS -o | grep -q "image/png"; then
|
||||
random=$(tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 16)
|
||||
file="$DESTINATION/$random.png"
|
||||
|
||||
xclip -selection clipboard -t image/png -o > $file
|
||||
echo "Image successfully saved as $random.png"
|
||||
echo ""
|
||||
pasteToArea ""
|
||||
|
||||
# replacing the new paste with old image
|
||||
xclip -selection clipboard -t image/png -i "$file"
|
||||
else
|
||||
|
||||
echo "Error: No image found in the clipboard!"
|
||||
fullfilepath=$(xclip -selection clipboard -o)
|
||||
|
||||
|
||||
|
||||
filename=$(basename -- "$fullfilepath")
|
||||
extension="${filename##*.}"
|
||||
filename_with_noext="${filename%.*}"
|
||||
file="$DESTINATION/$filename_with_noext $(date +%s).$extension"
|
||||
|
||||
if [[ $mode == "alt" ]]; then
|
||||
pasteToArea "[$filename](<$fullfilepath>)"
|
||||
# replacing the new paste with old one
|
||||
echo -n "$fullfilepath" | xclip -selection clipboard
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cp "$fullfilepath" "$file"
|
||||
echo "[$filename](<$file>)"
|
||||
pasteToArea "[$filename](<$file>)"
|
||||
|
||||
# replacing the new paste with old one
|
||||
echo -n "$fullfilepath" | xclip -selection clipboard
|
||||
fi
|
||||
|
||||
```
|
||||
|
||||
this will have absolute paths which can be resolved by adding a script on save in zed settings.jsonc file
|
||||
```json
|
||||
"languages": {
|
||||
"Markdown": {
|
||||
"format_on_save": "on",
|
||||
"formatter": {
|
||||
"external": {
|
||||
"command": "python3",
|
||||
"arguments": [
|
||||
"-c",
|
||||
"import sys, re, os\n\ncurrent_dir = os.path.dirname('{buffer_path}')\npattern = re.compile(r'(\\!?\\[.*?\\]\\()([^\\)]+)(\\))')\n\ndef replacer(match):\n prefix, path, suffix = match.groups()\n p = path.strip('<>')\n if os.path.isabs(p) and os.path.exists(p):\n return f'{prefix}{os.path.relpath(p, current_dir)}{suffix}'\n return match.group(0)\n\ntext = sys.stdin.read()\nsys.stdout.write(pattern.sub(replacer, text))"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
238
joplin notion extension/linux/mint/installing software.md
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
installing software
|
||||
|
||||
for brave
|
||||
|
||||
```sh
|
||||
sudo apt install curl
|
||||
|
||||
sudo curl -fsSLo /usr/share/keyrings/brave-browser-archive-keyring.gpg https://brave-browser-apt-release.s3.brave.com/brave-browser-archive-keyring.gpg
|
||||
|
||||
echo "deb [signed-by=/usr/share/keyrings/brave-browser-archive-keyring.gpg] https://brave-browser-apt-release.s3.brave.com/ stable main"|sudo tee /etc/apt/sources.list.d/brave-browser-release.list
|
||||
|
||||
sudo apt update
|
||||
|
||||
sudo apt install brave-browser
|
||||
```
|
||||
|
||||
for vlc
|
||||
`sudo apt install vlc`
|
||||
|
||||
librewolf
|
||||
```sh
|
||||
sudo apt update && sudo apt install extrepo -y
|
||||
|
||||
sudo extrepo enable librewolf
|
||||
|
||||
sudo apt update && sudo apt install librewolf -y
|
||||
```
|
||||
|
||||
haruna
|
||||
`sudo apt install haruna`
|
||||
|
||||
### similarly
|
||||
|
||||
similarly htop, mpv,btop,qutebrowser, micro,tmux, lsd, ark , qbittorent,thunderbird , okular , flameshot , kazam, openjdk, riseupvpn , handbrake , vim , neovim , mariadb-server , copyq
|
||||
|
||||
installed protonvpn through
|
||||
`flatpak install flathub com.protonvpn.www`
|
||||
to remove it
|
||||
`flatpak uninstall flathub com.protonvpn.www`
|
||||
|
||||
and to list packages
|
||||
`flatpak list`
|
||||
|
||||
this wasnt working so using openvpn
|
||||
|
||||
Get OpenVPN config files from Proton VPN:
|
||||
|
||||
Go to https://account.protonvpn.com/downloads
|
||||
|
||||
Scroll to OpenVPN Configuration Files section
|
||||
|
||||
Choose your platform:
|
||||
|
||||
Platform: Linux
|
||||
|
||||
Protocol: UDP or TCP (UDP is faster)
|
||||
|
||||
Download config(s) for the server(s) you want (e.g. JP-FREE.ovpn, US-FREE.ovpn)
|
||||
|
||||
3. Import the .ovpn file into NetworkManager:
|
||||
|
||||
Open Network Manager:
|
||||
|
||||
Click the network icon in your Cinnamon panel
|
||||
|
||||
Choose Network Settings
|
||||
|
||||
Click the + to add a new VPN
|
||||
|
||||
Choose Import from file...
|
||||
|
||||
Select the .ovpn file you downloaded
|
||||
|
||||
Enter your Proton VPN credentials:
|
||||
|
||||
Username and password (from your Proton VPN account dashboard, under OpenVPN / WireGuard login — these are different from your Proton email/password!)
|
||||
|
||||
Save & connect.
|
||||
|
||||
|
||||
**best method is to use wireguard**
|
||||
1. download wiregard profiles from https://account.protonvpn.com/downloads
|
||||
2. install wireguard-tools and then copy that conf files to `/etc/wireguard`
|
||||
3. run `sudo wg-quick up <conf_name>` (without .conf at end)
|
||||
4. to disconnect `sudo wg-quick down <conf_name>`
|
||||
Note : in proton config files, it is configured such that browsers cant access it so make changes in conf files like this
|
||||
`AllowedIPs = 0.0.0.0/0, ::/0` to allow all network traffic
|
||||
|
||||
|
||||
|
||||
|
||||
dev tools
|
||||
python3-pip, git,
|
||||
|
||||
other tools
|
||||
tldr,live-server, surge through npm,
|
||||
|
||||
|
||||
programs installed
|
||||
xdm ,
|
||||
fastfetch
|
||||
by
|
||||
```sh
|
||||
sudo add-apt-repository ppa:zhangsongcui3371/fastfetch
|
||||
sudo apt update
|
||||
sudo apt install fastfetch
|
||||
```
|
||||
keepaasxc by
|
||||
```sh
|
||||
sudo add-apt-repository ppa:phoerious/keepassxc
|
||||
sudo apt update
|
||||
sudo apt install keepassxc
|
||||
```
|
||||
|
||||
kooha by flathub
|
||||
```sh
|
||||
flatpak install flathub io.github.seadve.Kooha
|
||||
# then
|
||||
flatpak run io.github.seadve.Kooha
|
||||
|
||||
```
|
||||
|
||||
raider through flathub
|
||||
`flatpak install flathub com.github.ADBeveridge.Raider`
|
||||
|
||||
**android studio** by downloading its `android-studio-2024.3.2.14-linux.tar.gz` file from their page and then moved that extracted folder to `/usr/local` and then running ./studio from that location which wuld be under bin of that folder.
|
||||
|
||||
signal
|
||||
|
||||
```sh
|
||||
# NOTE: These instructions only work for 64-bit Debian-based
|
||||
# Linux distributions such as Ubuntu, Mint etc.
|
||||
|
||||
# 1. Install our official public software signing key:
|
||||
wget -O- https://updates.signal.org/desktop/apt/keys.asc | gpg --dearmor > signal-desktop-keyring.gpg
|
||||
cat signal-desktop-keyring.gpg | sudo tee /usr/share/keyrings/signal-desktop-keyring.gpg > /dev/null
|
||||
|
||||
# 2. Add our repository to your list of repositories:
|
||||
echo 'deb [arch=amd64 signed-by=/usr/share/keyrings/signal-desktop-keyring.gpg] https://updates.signal.org/desktop/apt xenial main' |\
|
||||
sudo tee /etc/apt/sources.list.d/signal-xenial.list
|
||||
|
||||
# 3. Update your package database and install Signal:
|
||||
sudo apt update && sudo apt install signal-desktop
|
||||
```
|
||||
|
||||
|
||||
sublime text 3
|
||||
```sh
|
||||
wget -qO - https://download.sublimetext.com/sublimehq-pub.gpg | sudo apt-key add -
|
||||
|
||||
echo "deb https://download.sublimetext.com/ apt/stable/" | sudo tee /etc/apt/sources.list.d/sublime-text.list
|
||||
|
||||
sudo apt update
|
||||
sudo apt install sublime-text
|
||||
|
||||
```
|
||||
|
||||
throium deb through official site, simlar tor-browser binary, xdm through downloading zip file and installing it with script : xdman, dua through binary zip
|
||||
|
||||
|
||||
**video-downloader** (gui for yt-dlp) : https://github.com/Unrud/video-downloader
|
||||
|
||||
instaling dependencies
|
||||
` sudo apt install ffmpeg libadwaita-1-0 yt-dlp meson build-essential libglib2.0-dev cmake librsvg2-bin libadwaita-1-dev libgtk-4-dev`
|
||||
|
||||
steps
|
||||
```sh
|
||||
git clone https://github.com/Unrud/video-downloader.git
|
||||
cd video-downloader
|
||||
|
||||
meson setup build --prefix=$HOME/video-downloader
|
||||
ninja -C build
|
||||
ninja -C build install
|
||||
```
|
||||
now glibschema needs to be setup too
|
||||
first copy data folder of project to ~/video-downloader then generate compiled version of this
|
||||
```sh
|
||||
glib-compile-schemas ~/video-downloader/data
|
||||
```
|
||||
or better yet
|
||||
```sh
|
||||
mkdir -p ~/.local/share/glib-2.0/schemas/
|
||||
cp build/data/com.github.unrud.VideoDownloader.gschema.xml ~/.local/share/glib-2.0/schemas/
|
||||
glib-compile-schemas ~/.local/share/glib-2.0/schemas/
|
||||
```
|
||||
|
||||
|
||||
|
||||
redis
|
||||
```sh
|
||||
sudo apt-get install lsb-release curl gpg
|
||||
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
|
||||
sudo chmod 644 /usr/share/keyrings/redis-archive-keyring.gpg
|
||||
echo "deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list
|
||||
sudo apt-get update
|
||||
sudo apt-get install redis
|
||||
```
|
||||
|
||||
|
||||
mongodb
|
||||
```sh
|
||||
sudo apt-get install gnupg curl
|
||||
curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | \
|
||||
sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg \
|
||||
--dearmor
|
||||
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
|
||||
sudo apt-get update && sudo apt-get install mongodb-org
|
||||
```
|
||||
|
||||
finally enable it
|
||||
`sudo systemctl start mongod`
|
||||
|
||||
|
||||
cloudflare warp
|
||||
```sh
|
||||
curl -fsSL https://pkg.cloudflareclient.com/pubkey.gpg | sudo gpg --yes --dearmor --output /usr/share/keyrings/cloudflare-warp-archive-keyring.gpg
|
||||
echo "deb [signed-by=/usr/share/keyrings/cloudflare-warp-archive-keyring.gpg] https://pkg.cloudflareclient.com/ $(. /etc/os-release && printf $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/cloudflare-client.list
|
||||
apt update && apt install cloudflare-warp
|
||||
```
|
||||
|
||||
|
||||
|
||||
calligra
|
||||
|
||||
now i3
|
||||
`apt install i3`
|
||||
|
||||
|
||||
|
||||
installing tailscale
|
||||
https://tailscale.com/docs/install/linux
|
||||
`curl -fsSL https://tailscale.com/install.sh | sh`
|
||||
|
||||
to start tailscale and enable ssh with it
|
||||
`sudo tailscale up --ssh`
|
||||
|
||||
installing openssh
|
||||
`sudo apt install openssh-server`
|
||||
230
joplin notion extension/linux/mint/nix_guide/basics.md
Normal file
|
|
@ -0,0 +1,230 @@
|
|||
basics
|
||||
|
||||
Absolutely — using **Nix** on Debian can give you a powerful, AUR-like experience with access to thousands of packages, isolated environments, and even rollbacks. It’s a different mindset than `apt`, but super powerful once you get the hang of it.
|
||||
|
||||
---
|
||||
|
||||
## 🧰 What Is Nix?
|
||||
|
||||
Nix is a **purely functional package manager**:
|
||||
|
||||
* Installs packages **without interfering** with your system.
|
||||
* Supports **per-user installs** — no sudo needed for most things.
|
||||
* Enables **isolated dev environments**, rollbacks, and reproducibility.
|
||||
|
||||
---
|
||||
|
||||
## 🧱 Step-by-Step: Installing and Using Nix on Debian
|
||||
|
||||
### 🔹 1. **Install Nix**
|
||||
|
||||
Run this script (official installer):
|
||||
|
||||
```bash
|
||||
curl -L https://nixos.org/nix/install | sh
|
||||
```
|
||||
|
||||
> ✅ After installation, either restart your shell or run:
|
||||
|
||||
```bash
|
||||
. ~/.nix-profile/etc/profile.d/nix.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🔹 2. **Install a Package (like `hello`)**
|
||||
|
||||
```bash
|
||||
nix-env -iA nixpkgs.hello
|
||||
```
|
||||
|
||||
> This installs the `hello` program into your **user profile** — no sudo needed.
|
||||
|
||||
You can run it immediately:
|
||||
|
||||
```bash
|
||||
hello
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🔹 3. **Search for Packages**
|
||||
|
||||
```bash
|
||||
nix search nixpkgs firefox
|
||||
```
|
||||
|
||||
Or use the web search: [https://search.nixos.org/packages](https://search.nixos.org/packages)
|
||||
|
||||
---
|
||||
|
||||
### 🔹 4. **Upgrade Installed Packages**
|
||||
|
||||
```bash
|
||||
nix-env --upgrade
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 🔹 5. **Remove a Package**
|
||||
|
||||
```bash
|
||||
nix-env -e hello
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Bonus: Reproducible Dev Environments (`shell.nix`)
|
||||
|
||||
Make a file named `shell.nix`:
|
||||
|
||||
```nix
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
|
||||
pkgs.mkShell {
|
||||
buildInputs = [
|
||||
pkgs.git
|
||||
pkgs.nodejs
|
||||
pkgs.python3
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
Then run:
|
||||
|
||||
```bash
|
||||
nix-shell
|
||||
```
|
||||
|
||||
This drops you into an environment with only those tools installed — perfect for development!
|
||||
|
||||
---
|
||||
|
||||
## 🔐 Is It Safe?
|
||||
|
||||
Yes — it’s **sandboxed**, doesn't touch your global system files, and is trusted by many in the DevOps/Dev world.
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Things to Know
|
||||
|
||||
* It uses a **huge store** (`/nix/store`) — so expect some disk usage.
|
||||
* It can be a **learning curve**, but well worth it if you want reproducibility or project-based environments.
|
||||
* You can uninstall Nix any time with `nix-env --uninstall` or delete `/nix`.
|
||||
|
||||
---
|
||||
|
||||
Want to try installing a specific package with Nix now, or explore using `home-manager` for managing your full dotfiles setup?
|
||||
|
||||
|
||||
|
||||
**Installing packages**
|
||||
|
||||
To install **Brave** using **Nix**, you have a couple of options depending on how you want to use it (system-wide, user profile, or temporary). Here's how to do it:
|
||||
|
||||
---
|
||||
|
||||
## 🦁 Option 1: Install Brave to Your User Profile (Permanent)
|
||||
|
||||
First, search for it:
|
||||
|
||||
```bash
|
||||
nix search nixpkgs brave
|
||||
```
|
||||
|
||||
You should see a result like:
|
||||
|
||||
```text
|
||||
brave # A privacy-focused web browser
|
||||
```
|
||||
|
||||
Then install it:
|
||||
|
||||
```bash
|
||||
nix-env -iA nixpkgs.brave
|
||||
```
|
||||
|
||||
✅ This makes `brave` available permanently in your user environment.
|
||||
|
||||
---
|
||||
|
||||
## ⚡ Option 2: Use `nix shell` (Temporary)
|
||||
|
||||
If you just want to **run Brave without installing**:
|
||||
|
||||
```bash
|
||||
nix shell nixpkgs#brave
|
||||
```
|
||||
|
||||
This will drop you into a shell where `brave` is available. You can launch it:
|
||||
|
||||
```bash
|
||||
brave
|
||||
```
|
||||
|
||||
When you exit the shell, it's gone — no clutter!
|
||||
|
||||
---
|
||||
|
||||
## 🔥 Option 3: Use `nix run` (One-off Execution)
|
||||
|
||||
To run Brave **directly**:
|
||||
|
||||
```bash
|
||||
nix run nixpkgs#brave
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📦 Bonus: Use `home-manager` (for managing user packages declaratively)
|
||||
|
||||
If you're managing your dotfiles/config with Nix, you can declare Brave in your `home.nix` like this:
|
||||
|
||||
```nix
|
||||
{
|
||||
home.packages = with pkgs; [
|
||||
brave
|
||||
];
|
||||
}
|
||||
```
|
||||
|
||||
Then just run `home-manager switch`.
|
||||
|
||||
---
|
||||
|
||||
Would you like help setting up `home-manager` too? It's great if you're building a Nix-based setup.
|
||||
|
||||
|
||||
|
||||
|
||||
for enabling expermimental feature which is required for search and install packages
|
||||
```sh
|
||||
sudo mkdir -p /etc/nix
|
||||
sudo nano /etc/nix/nix.conf
|
||||
```
|
||||
then add following
|
||||
```txt
|
||||
experimental-features = nix-command flakes
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
to remove packages
|
||||
|
||||
if installed with nix-env
|
||||
```sh
|
||||
nix-env -e brave
|
||||
```
|
||||
and then
|
||||
|
||||
for removing unused packages
|
||||
```sh
|
||||
nix-collect-garbage
|
||||
|
||||
```
|
||||
|
||||
for older generations:
|
||||
```sh
|
||||
nix-collect-garbage -d
|
||||
```
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
repair grub after installing windows
|
||||
|
||||
https://www.youtube.com/watch?v=Zr9oyWjD6IA
|
||||
https://askubuntu.com/questions/88384/how-can-i-repair-grub-how-to-get-ubuntu-back-after-installing-windows
|
||||
|
||||
1. use ` sudo fdisk -l` to find efi and main linux partition
|
||||
2. Mount linux partition to mnt. `sudo mount /dev/sdxy .mnt` and then mount efi partition to `/mnt/boot/efi`. `sudo mount /dev/sdab .mnt/boot/efi`.
|
||||
3. chroot to /mnt to access linux partition and then `update-grub`. Though most probably have to do this step too `grub-install /dev/sda` sda here but it have to be the drive where efi is installed
|
||||
4. finally exit and reboot
|
||||
|
||||
and if installed distri is arch based then
|
||||
while in chroot do following
|
||||
`grub-mkconfig -o /boot/grub/grub.cfg`
|
||||
then
|
||||
`grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=GRUB`
|
||||
59
joplin notion extension/linux/network issues.md
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
use the following command to check list of services
|
||||
|
||||
`systemctl list-units --type=service -all`
|
||||
|
||||
`sudo service --status-all`
|
||||
|
||||
https://pastes.dev/JNJEXP76gs
|
||||
|
||||
|
||||
|
||||
- to get a list of specs of system
|
||||
|
||||
`inxi -Fxxxrz && rfkill list && lsusb && mokutil --sb-state`
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
for debugging
|
||||
|
||||
`dmseg` : list how network is trying to connect
|
||||
|
||||
`networkctl`
|
||||
|
||||
`sudo systemctl enable --now NetworkManager`
|
||||
|
||||
`resolvectl and ip a`
|
||||
|
||||
|
||||
|
||||
list for drivers
|
||||
|
||||
`lspci -v`
|
||||
|
||||
[netlog.txt](../../_resources/netlog.txt)
|
||||
|
||||
[jornetlog.txt](../../_resources/jornetlog.txt)
|
||||
- if wifi stops working then
|
||||
- troublehsooting way : pressing power button for 20s when laptop is closed. while doing this step make sure all peripheral is disconnected too. then finally power on laptop normally
|
||||
- if above didnt solve issue then simply install wifi driver from `yay -Ss rtw` . for mine it is `rtw88-...` so install that package and reboot and it would work.
|
||||
- using modprobe way
|
||||
`lsmod | grep rtw` to get wifi module name
|
||||
`sudo modinfo rtw88-8723de`
|
||||
and
|
||||
`sudo modprobe -r rtw88_8723de && sudo modprobe rtw88_8723de`
|
||||
- found this solution too but idk if its safe and what it will do to battery life?
|
||||
https://bbs.archlinux.org/viewtopic.php?id=260589
|
||||
- tips
|
||||
- to get the live log
|
||||
`journalctl -xef`
|
||||
for normal log
|
||||
`journalctl -xe`
|
||||
- to get drivers
|
||||
`lspci -nnk`
|
||||
|
||||
https://aur.archlinux.org/packages/rtw88-fixed-firmware-git
|
||||
|
||||
- wifi router channel issues
|
||||
https://broadband.forum/threads/how-to-update-wifi-channels-on-reliance-jio-fiber-jco4032.205400/
|
||||
163
joplin notion extension/linux/rooting.md
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
rooting
|
||||
|
||||
lineageos device toplist
|
||||
[lineageos_device_toplist.txt](../../_resources/lineageos_device_toplist.txt)
|
||||
|
||||
for redmi 9 power
|
||||
https://thecustomrom.com/crdroid-with-android-11-for-redmi-9t-redmi-note-9-4g-redmi-9-power-poco-m3-juice/
|
||||
https://sourceforge.net/projects/crdroid/files/chime/8.x/
|
||||
https://www.youtube.com/watch?v=oOXQ7XhqeWk : unlocking bootloader
|
||||
https://www.youtube.com/watch?v=Ia4vQOP35Xo : ""
|
||||
https://xmfirmwareupdater.com/miui/lime/stable/V14.0.2.0.SJQINXM/ : stock firmware
|
||||
|
||||
redmi 9
|
||||
https://xdaforums.com/t/guide-unlock-lock-mi-bootloader-no-waiting-no-mobile-data.4695814/
|
||||
|
||||
redmi 6a:
|
||||
https://xdaforums.com/t/how-can-i-force-unlock-redmi-6as-bootloader-on-linux.4688558/
|
||||
|
||||
moto g82 5g
|
||||
rhodep lineageos 23 android 16
|
||||
|
||||
|
||||
yt videos
|
||||
part 1 (intro) : https://www.youtube.com/watch?v=DsyxajudDW8&t=5s
|
||||
part 2 (rooting) : https://www.youtube.com/watch?v=SqJArNiMJJM
|
||||
part 3 (custom rom ) : https://www.youtube.com/watch?v=ASkgmS_qyV8
|
||||
More refer links
|
||||
https://xdaforums.com/t/unable-to-install-any-twrp-image-on-my-nokia-6-1-2018-getting-stuck-on-splash-screen.4439147/#post-87839587 : for nokia 6.1
|
||||
https://www.reddit.com/r/LineageOS/comments/n7yo7u/a_discussion_about_bootloader_lockingunlocking/ : guide for bootloader unlocking
|
||||
|
||||
- unlock bootloader.
|
||||
official way for xiaomi : https://www.getdroidtips.com/unlock-bootloader-any-xiaomi-devices/
|
||||
Note : in HyperOS, you need to apply for unlocking in the Mi Community app, to be able to unlock bootloader. need an account at least 30 days old, and is recommended to switch region to UK in the app when doing it. but, for me personally it always says application quota reached so they're making it very hard
|
||||
for miui : in order to unlock bootloader just enteriing to fastboot is not enough, you need to have a sim in your phone then connect to mi account and make sure that number which is connected to mi account , have mobile data too for verifying then install some app and maybe if you are lucky your account will be approved. And then you need to wait for 7 days too
|
||||
or use this unofficial method : https://github.com/bkerler/mtkclient
|
||||
for hyperos unofficial method : https://github.com/mrzzoxo/HyperOS-BootLoader-Bypass/releases/tag/V2
|
||||
For nokia 6.1 use this guide https://www.techmesto.com/guide-unlock-bootloader-nokia-android-phones/ to unlock bootloader and make sure to install nokia drivers from here
|
||||
https://www.techmesto.com/download-minimal-adb-and-fastboot-latest/
|
||||
https://www.youtube.com/watch?v=HaGCEceu5JI
|
||||
Files:
|
||||
Nokia Drivers Disk 1.4.0.zip https://files.catbox.moe/hye5ym.zip (for windows )
|
||||
Nokia Bootloader Unlock Tool.zip https://files.catbox.moe/f68yt6.zip (for windows )
|
||||
Nokia Drivers must be installed so that your device is recognized in fastboot mode
|
||||
- rooting
|
||||
1. Reboot your phone to fastboot mode ie by pressing vol button + power or type `adb reboot bootloader` . in windows instead of `adb` use `.\adb` when into the folder where all these executables present
|
||||
2. Then type `fastboot devices` to check devices in fastboot mode. For windows make sure to install minimal adb and fastboot tool . Note in case of linux if get permissions error then use sudo with preferably `sudo ${which fastboot} devices`.
|
||||
https://www.youtube.com/watch?v=caMdjyDSMCY
|
||||
3. Now to check status if device is unlocked or not type this `fastboot oem device-info`.
|
||||
4. If it is not unlocked use various commands like `fastboot oem unlock` or `fastboot flashing unlock` . Now user have to navigate through volume button and chose yes to unlock bootloader. This will wipe all data though
|
||||
5. There are several methods for recovery mode. One of main method is twrp. Make sure to find twrp file for your model by going to their site https://twrp.me/Devices/ ( for nokia it is https://twrp.me/nokia/nokia61plus.html).
|
||||
If not found then check for this in xdm forums or at https://unofficialtwrp.com/ . for redmi one such example is https://unofficialtwrp.com/twrp-3-5-0-root-redmi-9-power/
|
||||
6. Boot Image Patching method : Without twrp method
|
||||
First we need boot image file and then magisk manager
|
||||
So for that we need to download firmware of phone which can be downloaded from company site but if not available it can be found in https://firmwarefile.com/
|
||||
for nokia 6.1 it is in
|
||||
https://www.mediafire.com/file/3eopqr6ll0qlqh3/Nokia_6.1_Plus_B2N-354H-0-00WW-B01_OST.zip
|
||||
firmware are of nb0 extenstion. to unpack use this tool
|
||||
[NB0_Tools_FIH_Mobile_v3.4.zip](../../_resources/NB0_Tools_FIH_Mobile_v3.4.zip) (for windows)
|
||||
|
||||
|
||||
7. TWRP method : Make sure to have magisk.zip and twrp img file for your model and just in case have magisk manager app on your pc. To boot phone to trwp mode type this `fastboot boot C:\Users\username\Downloads\twrp-3.3.1-1-PL2.img` or `fastboot boot C:\Users\hp\Downloads\twrp-3.4.0-0-PL2_sprout-11.0-20200909.img` . this another twrp because nokia 6.1 uses a/b paritions so maybe this helps .
|
||||
twrp link : https://xdaforums.com/attachments/twrp-img.5604269/
|
||||
magisk zip link : https://github.com/topjohnwu/Magisk/releases/download/v20.1/Magisk-v20.1.zip
|
||||
magisk manager link : https://github.com/topjohnwu/Magisk/releases/download/manager-v7.4.0/MagiskManager-v7.4.0.apk
|
||||
If used this command `fastboot flash recovery twrp.img` then maybe your device stuck and very difficult to get back to boot device.
|
||||
or maybe this is safer.
|
||||
```sh
|
||||
fastboot flash recovery twrp.img
|
||||
fastboot oem reboot-recovery
|
||||
|
||||
```
|
||||
- Make sure to that current slot is a not b. Current slot can be checked by `adb getvar current-slot` and to change it `adb --set-active=a`.
|
||||
- Then clickread only and the with adb sideload, sideload magisk.zip file with `adb sideload magisk.zip` .
|
||||
- Then finally go to masgisk manager and install recommened and u r done. your device is not rooted. Now whenever some app or service require root access it will give a dialog box waiting for allow. For adb , go to adb shell and type su and enter to request dialog box.
|
||||
More twrp build for nokia : https://nokia-sdm660.github.io/
|
||||
from https://xdaforums.com/t/closed-unofficial-twrp-3-4-0-0-team-win-recovery-project-nokia-6-1-plate2.4122949/
|
||||
|
||||
|
||||
- Linux issues
|
||||
Sometimes linux may not be able to perform any specific action due to udev rules . in case of debian it is plugdev and in arch it is uucp group so add your user in that group and now run some commands.
|
||||
Note : To get vendor id type `lsusb` and when mobile device is found. check the vendor id like XXXX:YYYY where XXXX is vendor id and YYYY is product id.
|
||||
```bash
|
||||
sudo usermod -aG uucp $(whoami)
|
||||
sudo nano /etc/udev/rules.d/51-android.rules
|
||||
# type this when in editor . (Replace `XXXX` with your device's vendor ID).
|
||||
SUBSYSTEM=="usb", ATTR{idVendor}=="XXXX", MODE="0666", GROUP="uucp"
|
||||
# then exit
|
||||
|
||||
# for reloading dev rules
|
||||
sudo udevadm control --reload-rules
|
||||
sudo udevadm trigger
|
||||
|
||||
```
|
||||
|
||||
|
||||
- changing slot
|
||||
https://www.youtube.com/watch?v=S_i7OIlP-wM
|
||||
- flashing stock rom
|
||||
https://www.youtube.com/watch?v=OMZ9uEPK4mc
|
||||
|
||||
|
||||
|
||||
|
||||
- Custom Rom
|
||||
- redmi 6a : https://theupgradeguide.com/install-android-9-0-pie-on-redmi-6a-lineageos-16-how-to-guide/
|
||||
and https://xdaforums.com/t/rom-unofficial-cactus-custom-roms-by-megafon929.4242535/page-2
|
||||
- https://www.youtube.com/watch?v=E82AZIOIaDc : installing twrp in redmi 6a
|
||||
|
||||
|
||||
nokia 6.1 install lineageos : https://wiki.lineageos.org/devices/PL2/install/
|
||||
https://xdaforums.com/t/official-lineageos-22-for-the-nokia-6-1-2018-6-1-plus.4649882/
|
||||
There are 2 types of custom rom mainly. One which is Stock but comes with tweaks, debloating , custom kernel etc. Other one are AOSP like lineageos, paranoid android, etc and have no oem stuff.
|
||||
A trick to identify type of custom roms is if zip files contains like 2 or 3 gb then its stock and if there are another for opengapps then it means that aosp is used.
|
||||
open gapps link : https://opengapps.org/
|
||||
Custom kernel adds functionality like better battery, increased performance etc
|
||||
While checking for kernel and opengpapps make sure to check android version and device support too for compability.
|
||||
it involved sideloading like we did in rooting , so go to trwp mode and then sideloading lineageos file basically, this may not work always so refer to lineageos docs
|
||||
|
||||
- Rooting after installing lineageos
|
||||
refer to this video too
|
||||
https://www.youtube.com/watch?v=8o5YILpoIvs
|
||||
and
|
||||
https://www.youtube.com/watch?v=269XcD6JK1U
|
||||
Steps are same but few things first. In settings of lineageos search for advanced restart and then enable it which gives option to boot into recovery mode.
|
||||
- When in reconvery mode go to apply update, apply adb then sideload masgisk zip file then it will warn you that signature verifiaion failed(bcz magisk is not made by same team as lineageos) but install anyway
|
||||
- What magisk does is patch the boot image file when 'install recommended' option is selected. so that can be done manually too by downloading the appropriate boot img file and then patch it then transfer patch to pc then use `fastboot flash boot magisk_patched_[random_string].img` and then reboot with `fastboot reboot`
|
||||
|
||||
|
||||
- Tips
|
||||
- If facing problem in random wifi disconnection then disable wifi mac address randomisation which maybe enabled by default. Oher solutions that might work, using wifi on airplane mode or turning private dns address off. Also disabling smart network switcher(switch between mobile data and wifi) might help.
|
||||
issue tracking of wifi problem : https://gitlab.com/LineageOS/issues/android/-/issues/5475
|
||||
and https://gitlab.com/LineageOS/issues/android/-/issues/7407
|
||||
- if rooting another rom while one rom is already there then make sure to wipe system parttion by booting into twrp mode
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
story
|
||||
- hey today i successfully unlocked bootloader and rooted my nokia 6.1. there was no official way so i have to use inofficila solution which required windows and when i unlocked bootloader and tyried to boot twrp i accidently briked my device and unbrick it withh stock rom and then booted into trwp recivery but faced hanging in android one logo so i need to be creative, started research and then changed my system partition from b to a, And then after booting into twrp recivery mode , i sideloaded magisk from adb and then finally used magisk manager to root it.
|
||||
|
||||
|
||||
|
||||
redmi 6a custom rom
|
||||
https://theupgradeguide.com/install-android-9-0-pie-on-redmi-6a-lineageos-16-how-to-guide/
|
||||
more
|
||||
https://xdaforums.com/t/rom-unofficial-cereus-custom-roms-by-megafon929.4242537/
|
||||
https://m929.ru/_pages/certus_my_builds.html
|
||||
and
|
||||
https://sourceforge.net/projects/adlinkousei/files/certus/
|
||||
use twrp or orangefox
|
||||
for orangefox extract zip downloaded from https://orangefox.download/device/60f1671c4447b54af15acc82 and extract it and use recovery.img to flash recovery
|
||||
`fastboot flash recovery recovery.img`
|
||||
`fastboot reboot recovery`
|
||||
in my case it was not booting to recovery just by this command an was booting normally to stock rom which repaced any sustom recovery installed so make sure to press vol up button after pressing power button for a bit and make sure to leave power button when it says unllocked otherwise it will just reboot. Timing is key here
|
||||
|
||||
**orangefox**
|
||||
1. format data and then wipe dalvik / art cache, system, data and cache.
|
||||
|
||||
|
||||
|
||||
sp flash tool
|
||||
https://spflashtools.com/category/linux/
|
||||
8
joplin notion extension/linux/share.md
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
https://m.youtube.com/watch?v=dcQdcf1Ckek
|
||||
|
||||
|
||||

|
||||
|
||||
https://www.debian.org/releases/bookworm/amd64/apds02.en.html
|
||||
|
||||

|
||||
48
joplin notion extension/linux/tmux.md
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
tmux
|
||||
https://www.youtube.com/watch?v=U41BTVZLKB0
|
||||
https://tmuxcheatsheet.com/
|
||||

|
||||
|
||||
|
||||
|
||||
- Start a new window with `tmux` command
|
||||
- At the bottom-left of screen there is `[0] 0:bash* `
|
||||
`[0]` : session name
|
||||
`0` from `0:bash` : index
|
||||
`bash` : windows name
|
||||
`*` : current window
|
||||
- to start a session with custom name use `tmux new -s backups` or `tmux new-session -s backups`. to rename current session use `c-b $`. to close the particular session use `tmux kill-ses -t session_name`. To close current session go to command mode by `c-b :` then type `kill-session` and hit enter.
|
||||
- to create a new window use `c-b c` means press Ctrl+B then release them and instantly press c.
|
||||
to go to next window press `c-b n` and to previous window `c-b p`. to specfic window index press `c-b INDEX`(eg: `c-b 1` to go to 2nd window as 2nd window index is 1). to kill current window use `c-b &`.
|
||||
- when we start a process say `htop` that window name will be changed to `htop`. but in order to change window to custom name press `c-b ,` then type type name and enter
|
||||
- **Attach/dettach mode**: If we start a service like nodejs code by `npm start` or any other and donr want terminal to be open and just run in background we need to detach it by `c-b d`. this will detach whole session.
|
||||
To reattach to recent session use `tmux a` or `tmux at`, `tmux attach`, `tmux attach-session`.
|
||||
To reattach to particular session use `tmux a -t backups` `-t` means target
|
||||
- to list tmux sessions use `tmux ls` or `tmux list-sessions`
|
||||
- **Switching** : when in tmux, to switch between sessions use `c-b s` which will presents a tui screen to choose session from and for windows switching use `c-b w`.
|
||||
- To get list of keyboard shotcuts use `c-b ?`
|
||||
- Splitting panes : To switch panes horizontally use `c-b %` and for vertically use `c-b "`. To go to last active pane press `c-b ;` and for navigating use `c-b arrow-keys` for respective direction.
|
||||
To close current pane use `c-b x`.
|
||||
- to scroll press `c-b [` then use arrowkeys/pgup/pgdown keys to scroll
|
||||
- **Icons** : start tmux with `tmux -u` to enable unicode support.
|
||||
|
||||
|
||||
automatic adding and running commands in tmux
|
||||
```sh
|
||||
#!/bin/bash
|
||||
|
||||
SESSION="my_session"
|
||||
|
||||
tmux new-session -d -s $SESSION
|
||||
|
||||
#C-m emulates pressing enter key
|
||||
tmux send-keys -t $SESSION:0 "htop" C-m
|
||||
|
||||
#create a new window of index 1 with name 'logs'
|
||||
tmux new-window -t $SESSION:1 -n "logs"
|
||||
tmux send-keys -t $SESSION:1 "history" C-m
|
||||
|
||||
tmux new-window -t $SESSION:2 -n "monitor"
|
||||
tmux send-keys -t $SESSION:2 "while true; do echo 'Monitoring...'; sleep 5; done" C-m
|
||||
|
||||
tmux attach-session -t $SESSION```
|
||||
6
joplin notion extension/linux/ubuntu server.md
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
ubuntu server
|
||||
|
||||
- use multiple tty to switch between sessions
|
||||
- credentials : `th`
|
||||
- `ssh -L 4000:localhost:3000 root@ssh.surf -p 9569`
|
||||
use this to login and expose the port 3000 of ssh container to 4000 of the current ones
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
unattended install of ubuntu server
|
||||
Video reference
|
||||
https://www.youtube.com/watch?v=DtXZ6BMaKbA
|
||||
https://files.catbox.moe/fztpyo.mp4
|
||||
|
||||
- Download iso from here: https://cdimage.ubuntu.com/releases/18.04.6/release/
|
||||
- Copy autoinstall-user-data file from `/var/log/installer` from where ubuntu-live-server-23.... .iso is installed. Then create a directory say 'server_work'. Under it create a autoinstall-user-data and copy necessary things like
|
||||
```
|
||||
#cloud-config
|
||||
autoinstall:
|
||||
identity:
|
||||
hostname: tree
|
||||
password: $6$oylcLD1tDk6UPHJf$xSwvFGR8314IlJBENXKKqAGbcHWuzPp7le3HRAzaSPg7I2vJk.pFEnMICyPOQwjJGjaPqejSEkPcyaG9T7kRW.
|
||||
realname: tree
|
||||
username: tree
|
||||
kernel:
|
||||
package: linux-generic
|
||||
keyboard:
|
||||
layout: us
|
||||
toggle: null
|
||||
variant: ''
|
||||
locale: en_US.UTF-8
|
||||
ssh:
|
||||
allow-pw: true
|
||||
authorized-keys: []
|
||||
install-server: true
|
||||
updates: security
|
||||
version: 1
|
||||
shutdown: poweroff
|
||||
|
||||
```
|
||||
- Now create directory 'source-files' and use this
|
||||
`xorriso -osirrox on -indev ubuntu-23.10-live-server-amd64.iso --extract_boot_images source-files/bootpart -extract / source-files/
|
||||
`
|
||||
- Now go to source-files dir and create dir nocloud and go to nocloud and use
|
||||
`cp ../../autoinstall-user-data user-data`. Now create file named meta-data. Finally go to parent dir ie source-files.
|
||||
- Now go to boot/grub and add write permission for root for file grub.cfg using `chmod 644 grub.cfg`
|
||||
- Open grub.cfg. Create menuentry for automatic install like this
|
||||
After the line `set menu_color_highlight=black/light-gray` add this
|
||||
```
|
||||
menuentry "Autoinstall Ubuntu Server" {
|
||||
set gfxpayload=keep
|
||||
linux /casper/vmlinuz quiet autoinstall ds=nocloud\;s=/cdrom/nocloud/ ---
|
||||
initrd /casper/initrd
|
||||
}
|
||||
|
||||
```
|
||||
and set timeout=5 instead of 30
|
||||
- Go to source files directory. Now use this
|
||||
`xorriso -as mkisofs -r -V "ubuntu-autoinstall" -J -boot-load-size 4 -boot-info-table -input-charset utf-8 -eltorito-alt-boot -b bootpart/eltorito_img1_bios.img -no-emul-boot -o ../installer.iso .`
|
||||
|
||||
|
||||
- ssh
|
||||
`sudo nano /etc/ssh/sshd_config`
|
||||
Change port if desired
|
||||
|
||||
`ssh username@ip_address -p 22` . here ip_address can be local or public. 22 is default port
|
||||
When port forwarding externally, using pyblic ip address make sure to have some firewall like `fail2ban` or `ufw`
|
||||
In order to use GUI locally when opening through ssh.
|
||||
for eg: opening gui in A if remote machine is B.
|
||||
`ssh -X userB@ip_address -p $DEFAULT_PORT`
|
||||
4
joplin notion extension/linux/vs code/c++ on vs code.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
c++ on vs code
|
||||
|
||||
- configuration
|
||||
Make sure that gdb is installed with `yay -S gdb` or other package manager then simply run it will autoconfigure
|
||||
64
joplin notion extension/manjaro/Basics.md
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
Basics
|
||||
|
||||
- To get a list of installed packages
|
||||
`pacman -Qqe`
|
||||
for all gtk packages
|
||||
`pacman -Qs gtk`
|
||||
for gtk version
|
||||
`pacman -Q gtk`
|
||||
|
||||
- To get list of package information including all dependencies it needs
|
||||
`pacman -Si nodejs`
|
||||
|
||||
|
||||
|
||||
|
||||
- downloading build files ie tar.zst
|
||||
you go to https://archlinux.org/packages/
|
||||
find the package you want
|
||||
in the top-right corner of the package's page, you click the download from mirror button, you do that for every package you want
|
||||
|
||||
- to get info of package
|
||||
`pamac info <pkg_name>`
|
||||
or
|
||||
`yay -Si <pkg_name>`
|
||||
|
||||
- to search repos and aur with keyword
|
||||
`yay -Ss straw` here straw is keyword
|
||||
|
||||
- to not reinstall package use
|
||||
`yay -S --needed strawberry`
|
||||
|
||||
- to get users and group list
|
||||
https://devconnected.com/how-to-list-users-and-groups-on-linux/
|
||||
`cat /etc/passwd | cut -d: -f1`
|
||||
`cat /etc/passwd | awk -F: '{print $1}'`
|
||||
For connected users:
|
||||
`who`
|
||||
or
|
||||
`users` for less details
|
||||
|
||||
For groups
|
||||
`cat /etc/group`
|
||||
About its output
|
||||
first col is group name
|
||||
sec col : password
|
||||
3rd: group id
|
||||
4th: users in the group
|
||||

|
||||

|
||||
- To complete remove packages
|
||||
`pacman -Rns package_name`
|
||||
The -Rns flags tell pacman to remove the packages, their configuration files (n), and their unneeded dependencies (s).
|
||||
- Removing orphan package completely
|
||||
First, you need to identify the orphaned packages. This can be done using the pacman package manager with the following command:
|
||||
|
||||
`pacman -Qdt`
|
||||
|
||||
|
||||
|
||||
To remove these orphaned packages, you can use the same pacman command with the remove (-R) option:
|
||||
|
||||
`pacman -Rns $(pacman -Qdtq)`
|
||||
- When installing packages from pacman and we dont want any prompt and want the feafult in `[y/n]` then use the flag `--noconfirm`
|
||||
`pacman -s firefox --noconfirm`
|
||||
188
joplin notion extension/manjaro/Extras.md
Normal file
|
|
@ -0,0 +1,188 @@
|
|||
|
||||
Extras
|
||||
|
||||
- For capturing streaming media : video downloadhelper extension https://www.downloadhelper.net/
|
||||
|
||||
- Joplin introduction : https://sdrive.app/s/c1inpfn6wle3aaczag6vtjud
|
||||
|
||||
- Reason for low battery life in linux
|
||||
When a computer is sold with Windows installed, it has ACPI and chipset drivers that can manage the CPU power and overall power consumption. These generally do not exist for Linux, so when the CPU is idle, it is still running the CPU clock at full speed. Similarly, there may be a temperature controlled fan that is dependent on some driver that Linux does not have, so the fan runs at full speed continuously.
|
||||
Some computers are supported by Linux and will not exhibit this behavior, but by no means is that true in all cases. I am guessing you have one that is not fully supported by Linux for power management. It may just be a matter of finding the right drivers and installing them. Or the driver may not be available for Linux at all.
|
||||
Things are quite a bit better than when I started out with Linux in 1992, but by no means are manufacturers making Linux drivers available for all the hardware out there. Some do, and if you are primarily interested in Linux on a notebook computer, you need to search out manufacturers that either offer Linux as an option or offer the ability to obtain hardware specific Linux drivers.
|
||||
|
||||
|
||||
- vscode python automcompletion issue
|
||||
Sometime pylance extension that is installed with microsoft python extension can cause error and disable autocomplete so disable it if u want to use autocomplete feature
|
||||
|
||||
- Optimized chromium for linux
|
||||
Thorium
|
||||
|
||||
- Best torrent client for linux
|
||||
qbitTorrent
|
||||
fragment for gnome
|
||||
transmissions for no gui/ssh
|
||||
|
||||
- Docker
|
||||
Use the following cpmmand to start docker service
|
||||
`sudo systemctl start docker.service`
|
||||
|
||||
This to enable it for permanent startup when booted
|
||||
`sudo systemctl enable docker.service`
|
||||
|
||||
|
||||
- quickgui
|
||||
https://docs.flutter.dev/release/archive?tab=linux : binaries
|
||||
https://github.com/quickemu-project/quickgui#install
|
||||
- Using it
|
||||
https://nonvalet.com/posts/20220610_quickemu/
|
||||
To start the VM:
|
||||
`cd ~/VMs`
|
||||
`quickemu --vm debian-10.0.0-xfce.conf --display spice`
|
||||
https://forums.opensuse.org/t/using-qemu-as-you-use-virtualbox/151738
|
||||
- Open source projects
|
||||
1. Pinephone : open source hardware
|
||||
2. https://github.com/makeplane/plane : Open Source JIRA, Linear and Height Alternative. Plane helps you track your issues, epics, and product roadmaps in the simplest way possible.
|
||||
3. GitHub - notable/notable: markdown note taking app similar to oplin with no mobile client
|
||||
|
||||
|
||||
|
||||
- Creating a limit of RAM for certain application
|
||||
`node --max-old-space-size=2048 yourScript.js`
|
||||
|
||||
- Manjaro mess
|
||||
https://manjarno.pages.dev/
|
||||
|
||||
- Compressions
|
||||
When comparing the various compressions, generally the tradeoff is time vs. size. gzip tends to compress and decompress relatively quickly while yielding a good compression ratio. bzip2 is somewhat slower than gzip both in compression and decompression time, but yields even greater compression ratios. LZMA has the longest compression time but yields the best ratios while also having a decompression rate outperforming that of bzip2.
|
||||
|
||||
- Incognito mode in terminal
|
||||
before you leave, type `unset HISTFILE`
|
||||
|
||||
- Hyperbola : arch based distro which is based on linux-libre kernel which is not supported in all machines. It is point based rather then rolling release
|
||||
- imagemagick : to have image manipulation. one truck is to convert to pdf from images
|
||||
`convert *.png -auto-orient pictures.pdf`
|
||||
also for compressing
|
||||
`convert input.png -define jpeg:extent=200KB output.jpg`
|
||||
for black png to gray png
|
||||
`convert icon.png +level-colors "rgb(102,102,102)" -transparent white result.png`
|
||||
- pipewire may be better than pulseaudio
|
||||
- change lock screen wallpaper
|
||||
https://forum.manjaro.org/t/howto-change-the-lock-screen-wallpaper-in-manjaro-xfce/112400
|
||||
Open the `LightDM Gtk+ Greeter: Settings` App from the apps menu
|
||||
|
||||
- Better start menu
|
||||
`pacman -S xfce4-whiskermenu-plugin`
|
||||
and
|
||||
in shortcut window found in Keyboard option in set
|
||||
tings manager add this command
|
||||
`xfce4-popup-whiskermenu`
|
||||

|
||||
|
||||
|
||||
- GPU and i/o usage at xfce panel
|
||||
1. First download these third party plugins ie `radeontop` for amd gpu, `nvidia-smi` for NVIDIA GPUs and `iotop` for disk usage.
|
||||
2. Make sure that `xfce4-genmon-plugin` is installed. if it isnt then install it.
|
||||
3. Now in xfce panel , right click -> panel->add new items->generic monitor.
|
||||
4. After adding right click on this new item and add command for displaying the output.
|
||||
Command is `radeontop -d - -l 1 | grep -Po "(?<=gpu )([0-9]*\.\d\d\%)"`
|
||||
`(?<=<pattern>)` this will exclude the gpu part
|
||||
5. But this command directly wont work. so write a script in .sh file and include its path in command section.
|
||||
```bash
|
||||
#!/bin/bash
|
||||
gpu_percent=$(radeontop -d - -l 1 | grep -Po "(?<=gpu )([0-9]*\.\d\d\%)")
|
||||
|
||||
echo " $gpu_percent"
|
||||
```
|
||||
|
||||
- Network usage of individual process
|
||||
install `nethogs` and `sudo nethogs` . It is a cli tool
|
||||
- Check firmware age
|
||||
`hostnamectl`
|
||||
- To optimize battery use
|
||||
`tlp`
|
||||
https://wiki.archlinux.org/title/CPU_frequency_scaling#Scaling_governors
|
||||
`sudo cpupower frequency-set -g powersave`
|
||||
also to disable usb auto suspend go to `micro /etc/tlp.conf` and change `USB_AUTOSUSPEND` to 0 and `remote_pm_on_bat` to on instead of auto and finally do
|
||||
`sudo tlp start`
|
||||
- To get information about video product use
|
||||
`ffprobe <video/audio file name>`
|
||||
or
|
||||
`mediainfo <video/audio file name>`
|
||||
- check video drivers
|
||||
`lspci | grep VGA`
|
||||
https://askubuntu.com/questions/28033/how-to-check-the-information-of-current-installed-video-drivers
|
||||
- check audio drivers
|
||||
- installing pipewire
|
||||
`sudo pacman -Syu pipewire pipewire-pulse pipewire-jack pipewire-alsa wireplumber`
|
||||
- installing pulseaudio
|
||||
`-Syu pulseaudio jack2`
|
||||
|
||||
- check if your u have systemd or not
|
||||
https://itsfoss.com/check-if-systemd/
|
||||
|
||||
- Funny parrot animation
|
||||
`curl parrot.live`
|
||||
- Handbrake cli
|
||||
```bash
|
||||
for file in *.mp4; do
|
||||
HandBrakeCLI -i "$file" -o "${file%.mp4}_encoded.mp4" --preset="Very Fast 720p30"
|
||||
done
|
||||
|
||||
```
|
||||
- Changing mirrors
|
||||
Go to `/etc/pacman.d/mirrorlist` and add mirror like
|
||||
```
|
||||
# India
|
||||
Server = https://mirror.albony.xyz/manjaro/stable/$repo/$arch
|
||||
```
|
||||
After copying mirror link append `stable/$repo/$arch`. First in the mirrorlist have most priority as priority order is from top to bottom.
|
||||
Use this site to get list of mirors:
|
||||
https://repo.manjaro.org/
|
||||
https://archlinux.org/mirrorlist/all/
|
||||
- Change relative paths in subdirectories too using bash script for md files
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# Set the old and new paths for the 'resource' folder
|
||||
old_resource_path="/home/hpes/Videos/imp/joplin_bkps/joplin-04-03-24/_resources/"
|
||||
new_resource_path="/home/hpes/Videos/imp/joplin_bkps/joplin-04-03-24/joplin notion extension/_resources/"
|
||||
|
||||
# Set the file extension you want to process (assuming it's .md)
|
||||
file_extension=".md"
|
||||
|
||||
# its the base path from where relative path is defined.
|
||||
# eg: if base path is '/home/user/downloads' and asset is in
|
||||
# /home/user/assets' then relative path assigned would be '../assets'
|
||||
BASE_DIR="/home/hpes/Videos/imp/joplin_bkps/joplin-04-03-24/joplin notion extension/Web Development/"
|
||||
|
||||
# Function to resolve relative paths
|
||||
resolve_relative_path() {
|
||||
local file_path="$1"
|
||||
local base_path="$2"
|
||||
echo "$(realpath --relative-to="$base_path" "$file_path")"
|
||||
|
||||
|
||||
}
|
||||
|
||||
# Loop through all .md files in the current directory and its subdirectories
|
||||
find "${BASE_DIR}" -type f -name "*${file_extension}" -print0 | while IFS= read -r -d '' file; do
|
||||
# Resolve relative paths in the file
|
||||
resolved_old_path=$(resolve_relative_path "${old_resource_path}" "$(dirname "${file}")")
|
||||
resolved_new_path=$(resolve_relative_path "${new_resource_path}" "$(dirname "${file}")")
|
||||
|
||||
# Update the relative paths in the file using sed
|
||||
sed -i "s|${resolved_old_path}|${resolved_new_path}|g" "${file}"
|
||||
# echo "${resolved_old_path} ${resolved_new_path} " "${file}"
|
||||
echo "Updated paths in ${file}"
|
||||
done
|
||||
|
||||
echo "Path update complete!"
|
||||
|
||||
```
|
||||
|
||||
- proton VPN country selection
|
||||
`pacman -S protonvpn-1.0.4` or whatever the specific version is
|
||||
proton_vpn_package_country_selection.zip https://files.catbox.moe/okizw9.zip
|
||||
- hiding text in images
|
||||
`echo "text to be hidden" >> image.png` now whenever image is opened with text editor we can see text at last
|
||||
echo_hide_text_technique.mp4 https://small.fileditchstuff.me/s6/hwauSmkAWsDeIluenclc.mp4
|
||||
4
joplin notion extension/manjaro/Good packages.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
Good packages
|
||||
|
||||
- cmus and moc for cli music player
|
||||
for moc, use mocp command
|
||||
42
joplin notion extension/manjaro/WINE installation.md
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
WINE installation
|
||||
https://wine.htmlvalidator.com/install-wine-on-arch-linux.html
|
||||
|
||||
- First enable multilib by
|
||||
`sudo nano /etc/pacman.conf`
|
||||
and uncomment following
|
||||
```
|
||||
[multilib]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
```
|
||||
sd
|
||||
- Full system upgrade
|
||||
`sudo pacman -Syu`
|
||||
|
||||
- Install Wine
|
||||
`sudo pacman -S wine wine-mono wine-gecko`
|
||||
To check use this
|
||||
`wine --version`
|
||||
|
||||
- Configuration
|
||||
`wine winecfg` or `wineboot`
|
||||
|
||||
- To install application use this
|
||||
`wine WinPgm-installer.exe` here WinPgm-installer.exe is exe file
|
||||
|
||||
- Installing wine web browser(Optional)
|
||||
`sudo pacman -S --needed samba gnutls lib32-gnutls`
|
||||
`wine iexplore`
|
||||
|
||||
- Installing dotnet
|
||||
`sudo pacman -S winetricks`
|
||||
`winetricks dotnet40` for net 4.0
|
||||
`winetricks dotnet461` for net 4.6.1
|
||||
- Installing proton
|
||||
proton-ge-custom from aur
|
||||
|
||||
|
||||
## for ubuntu
|
||||
- for instralling wine
|
||||
use wine-installer and make sure to `sudo apt update` before that
|
||||
then after installing lutris from guthub release sue this
|
||||
`GDK_BACKEND=x11 lutris` to run it
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
for installing ntfs driver
|
||||
`sudo pacman -Sy ntfs-3g`
|
||||
|
||||
for displaying partition information
|
||||
`lsblk`
|
||||
|
||||
For creating mount point
|
||||
|
||||
`sudo mount /dev/sda3 /run/media/hpm/HDD`
|
||||
12
joplin notion extension/manjaro/installations.md
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
installations
|
||||
|
||||
```
|
||||
To install (6):
|
||||
java-runtime-common 3-5 (Required By: jdk11-openjdk) extra 5.1 kB
|
||||
libnet 1:1.1.6-1 (Required By: jdk11-openjdk) extra 98.6 kB
|
||||
jre11-openjdk-headless 11.0.20.1.u1-1 (Required By: jdk11-openjdk) extra 37.8 MB
|
||||
jre11-openjdk 11.0.20.1.u1-1 (Required By: jdk11-openjdk) extra 197.9 kB
|
||||
java-environment-common 3-5 (Required By: jdk11-openjdk) extra 2.6 kB
|
||||
jdk11-openjdk 11.0.20.1.u1-1 extra 322.3 MB
|
||||
```
|
||||
- 
|
||||
210
joplin notion extension/manjaro/other issues.md
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
- fix time issues
|
||||
`timedatectl set-ntp true`
|
||||
`sudo systemctl enable --now systemd-timesyncd`
|
||||
|
||||
* * *
|
||||
|
||||
- Removing packages
|
||||
|
||||
```
|
||||
pamac --version
|
||||
pamac --help, -h [action]
|
||||
pamac search [options] <package(s)>
|
||||
pamac list [options] <package(s)>
|
||||
pamac info [options] <package(s)>
|
||||
pamac install [options] <package(s)>
|
||||
pamac reinstall [options] <package(s)>
|
||||
pamac remove [options] [package(s)]
|
||||
pamac checkupdates [options]
|
||||
pamac update,upgrade [options]
|
||||
pamac clone [options] <package(s)>
|
||||
pamac build [options] [package(s)]
|
||||
pamac clean [options]
|
||||
```
|
||||
|
||||
`yay -Sc` : for clearing cache
|
||||
|
||||
```
|
||||
List orphaned packages: `pamac list -o`
|
||||
```
|
||||
|
||||
Remove orphaned packages: `pamac remove -o`
|
||||
|
||||
Another thing to do is clean up extra copies of packages you don't need:
|
||||
|
||||
`pamac clean`
|
||||
|
||||
I have pamac set up to keep the last 3 versions of each package, so this will only remove excess packages while maintaining a couple of versions back in case I need to downgrade. I like using this method instead as it will handle flatpacks as well as native packages.
|
||||
|
||||
Here's an example:
|
||||
|
||||
```
|
||||
[Bester-PN50 ~]# pamac list -o
|
||||
lib32-fluidsynth 2.1.7-1 multilib 476.6 kB
|
||||
libgnome-games-support 1.8.0-1 extra 186.8 kB
|
||||
[Bester-PN50 ~]# pamac remove -o
|
||||
Preparing...
|
||||
Checking dependencies...
|
||||
|
||||
To remove (5):
|
||||
lib32-fluidsynth 2.1.7-1 multilib
|
||||
lib32-portaudio 1:19.6.0-4 (Orphan Of: lib32-fluidsynth) multilib
|
||||
lib32-sdl2 2.0.14-1 (Orphan Of: lib32-fluidsynth) multilib
|
||||
lib32-libinstpatch 1.1.6-1 (Orphan Of: lib32-fluidsynth) multilib
|
||||
libgnome-games-support 1.8.0-1 extra
|
||||
|
||||
Total removed size: 3.5 MB
|
||||
|
||||
Apply transaction ? [y/N] y
|
||||
Removing lib32-fluidsynth (2.1.7-1)... [1/5]
|
||||
Removing lib32-portaudio (1:19.6.0-4)... [2/5]
|
||||
Removing libgnome-games-support (1.8.0-1)... [3/5]
|
||||
Removing lib32-sdl2 (2.0.14-1)... [4/5]
|
||||
Removing lib32-libinstpatch (1.1.6-1)... [5/5]
|
||||
Running post-transaction hooks...
|
||||
Arming ConditionNeedsUpdate... [1/1]
|
||||
Transaction successfully finished.
|
||||
[Bester-PN50 ~]# pamac clean
|
||||
Number of versions of each package to keep in the cache: 3
|
||||
|
||||
To delete: 1 file (145.9 kB)
|
||||
Clean cache ? [y/N] y
|
||||
```
|
||||
|
||||
* * *
|
||||
|
||||
- Vscodium
|
||||
https://www.linuxcapable.com/how-to-install-vscodium-on-manjaro-linux/
|
||||
|
||||
|
||||
|
||||
- vpns installation
|
||||
`yay -S protonvpn-gui`
|
||||
|
||||
|
||||
- Symbolic links
|
||||
https://linuxhint.com/create-symbolic-links-manjaro/
|
||||
`ln -s [path-of-target-file] [path-of-symlink-file]`
|
||||
`ln -s linuxhint.txt symfile.txt`
|
||||
|
||||
**For verification of symbolic link**
|
||||
`ls -l sym_dir`
|
||||
|
||||
**For full path sym links**
|
||||
You can turn relative paths into full paths using readlink -f foo. So you would do something like:
|
||||
`ln -s $(readlink -f $origlink) $newlink`
|
||||
|
||||
- Building and installing packages from arch repos
|
||||
[https://wiki.archlinux.org/title/Arch\_User\_Repository](https://wiki.archlinux.org/title/Arch_User_Repository)
|
||||
https://wiki.archlinux.org/title/Makepkg
|
||||
|
||||
By default build tools are not available so install them using
|
||||
`sudo pacman -S base-devel`
|
||||
It will install these packages
|
||||
|
||||
```
|
||||
autoconf-2.71-4 automake-1.16.5-2 bison-3.8.2-6 debugedit-5.0-5 flex-2.6.4-5 gc-8.2.4-1 guile-3.0.9-1 m4-1.4.19-3 make-4.4.1-2 patch-2.7.6-10 pkgconf-1.8.1-1 base-devel-1-2
|
||||
```
|
||||
To build a package, one must first create a PKGBUILD, or build script, as described in Creating packages. Existing scripts are available from the Arch build system (ABS) tree or the AUR. Once in possession of a PKGBUILD, change to the directory where it is saved and run the following command to build the package:
|
||||
`makepkg`
|
||||
- strawberry
|
||||
|
||||
[strawberry-qt5-1.0.20-1-x86\_64.pkg.tar.zst](../../_resources/strawberry-qt5-1.0.20-1-x86_64.pkg.tar.zst)
|
||||
|
||||
- nordvpn
|
||||
Use this command
|
||||
`pamac install nordvpn-bin`
|
||||
|
||||
|
||||
\==> Making package: nordvpn-bin 3.16.6-1 (Friday 20 October 2023 11:42:49 PM)
|
||||
\==> Checking runtime dependencies...
|
||||
\==> Checking buildtime dependencies...
|
||||
\==> Retrieving sources...
|
||||
\-> Downloading nordvpn\_3.16.6\_amd64.deb...
|
||||
% Total % Received % Xferd Average Speed Time Time Time Current
|
||||
Dload Upload Total Spent Left Speed
|
||||
100 32.6M 100 32.6M 0 0 3656k 0 0:00:09 0:00:09 --:--:-- 3811k
|
||||
\==> Validating source\_x86\_64 files with sha256sums...
|
||||
nordvpn\_3.16.6\_amd64.deb ... Passed
|
||||
\==> Removing existing $srcdir/ directory...
|
||||
\==> Extracting sources...
|
||||
\-> Extracting nordvpn\_3.16.6\_amd64.deb with bsdtar
|
||||
\==> Entering fakeroot environment...
|
||||
\==> Starting package()...
|
||||
\==> Tidying install...
|
||||
\-> Removing libtool files...
|
||||
\-> Purging unwanted files...
|
||||
\-> Removing static library files...
|
||||
\-> Stripping unneeded symbols from binaries and libraries...
|
||||
\-> Compressing man and info pages...
|
||||
\==> Checking for packaging issues...
|
||||
\==> Creating package "nordvpn-bin"...
|
||||
\-> Generating .PKGINFO file...
|
||||
\-> Generating .BUILDINFO file...
|
||||
\-> Adding install file...
|
||||
\-> Generating .MTREE file...
|
||||
\-> Compressing package...
|
||||
\==> Leaving fakeroot environment.
|
||||
\==> Finished making: nordvpn-bin 3.16.6-1 (Friday 20 October 2023 11:43:17 PM)
|
||||
\==> Cleaning up...
|
||||
|
||||
Checking keyring... \[1/1\]
|
||||
Checking integrity... \[1/1\]
|
||||
Loading packages files... \[1/1\]
|
||||
Checking file conflicts... \[1/1\]
|
||||
Checking available disk space... \[1/1\]
|
||||
Installing nordvpn-bin (3.16.6-1)... \[1/1\]
|
||||
:: In order to enable nordvpn you have to start the following service:
|
||||
`sudo systemctl enable --now nordvpnd`
|
||||
:: You have to add yourself to the nordvpn group:
|
||||
`sudo gpasswd -a USERNAME nordvpn`
|
||||
:: You then have to restart for the group to be created:
|
||||
`reboot`
|
||||
|
||||
- offline installation
|
||||
from tar zst file do this
|
||||
`sudo pacman -U ./app-name.tar.zst`
|
||||
`sudo pacman -Sw stacer`
|
||||
`pamac install -w stacer` : not for AUR
|
||||
|
||||
[stacer-1.1.0-1-x86\_64.pkg.tar.zst](../../_resources/stacer-1.1.0-1-x86_64.pkg.tar.zst)
|
||||
|
||||
- nvm installation
|
||||
`curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash`
|
||||
|
||||
`nvm ls-remote` : for getting list of available versions which can be downloaded
|
||||
`nvm list` : for getting list of downloaded versions of node
|
||||
`nvm install 14.0.0` : for downloading and installing version 14.0.0
|
||||
`nvm use 14.0.0` : switching to version 14.0.0
|
||||
`nvm use system`: switching to version when nodejs first installed
|
||||
|
||||
|
||||
|
||||
- Checking for missing dependencies
|
||||
You can check if you have missing files from installed packages, e.g.:
|
||||
|
||||
$ `pacman -Qk qemu-system-x86`
|
||||
qemu-system-x86: 13 total files, 0 missing files
|
||||
|
||||
- cloudflare-warp installation
|
||||
install aur package ie cloudflare-warp-bin then use
|
||||
`warp-cli`
|
||||
if facing error ie daemon not running then use this command:
|
||||
`sudo systemctl enable --now warp-svc.service`
|
||||
Then
|
||||
https://blog.cloudflare.com/announcing-warp-for-linux-and-proxy-mode/
|
||||
```bash
|
||||
~$ warp-cli register
|
||||
Success
|
||||
~$ warp-cli connect
|
||||
```
|
||||
- Issues in cd
|
||||
If it says cd has too many arguments then wrap them in double quotes
|
||||
`cd "$PATH"`
|
||||
|
||||
- Forcing installation no matter if dependency breaks
|
||||
Use `--nodeps` flag with `pacman -S package_name`
|
||||
- history expansion issue
|
||||
When entering command it may be possible that some characters are there that needs to be escaped to avoid undesired results
|
||||
one such is `!` which is for history expansion. so make sure to escape it with `\!`.
|
||||
|
||||
116
joplin notion extension/manjaro/packages.md
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
- List
|
||||
1. https://www.idrive.com/idrive/sh/sh?k=k6i9r6e0e4 : vscode tar.zst
|
||||
2. https://www.idrive.com/idrive/sh/sh?k=h8s0b8v7s6 : icedrive
|
||||
3. https://www.idrive.com/idrive/sh/sh?k=r6p6l9n1q8 : electron
|
||||
4. https://www.idrive.com/idrive/sh/sh?k=q7u1r1b2q3 : brave
|
||||
5. https://www.idrive.com/idrive/sh/sh?k=q8p0c6b5r2 : vscodium
|
||||
6. https://www.idrive.com/idrive/sh/sh?k=b8i2x7z5i4 : floorp(firefox fork)
|
||||
7. https://www.idrive.com/idrive/sh/sh?k=e8c8q2c2i5 : thorium(chromium fork)
|
||||
8. https://www.idrive.com/idrive/sh/sh?k=e3x6g9q7s3 : tor browser
|
||||
9. https://www.idrive.com/idrive/sh/sh?k=b9z1w0r6g2 : flutter
|
||||
|
||||
[brave-browser-1.59.120-1-x86_64.pkg.tar.zst.sig](../../_resources/brave-browser-1.59.120-1-x86_64.pkg.tar.zst.sig)
|
||||
|
||||
- More
|
||||
1. Gdb:
|
||||
|
||||
|
||||
[gdb-13.2-1-x86_64.pkg.tar.zst](../../_resources/gdb-13.2-1-x86_64.pkg.tar.zst)
|
||||
|
||||
|
||||
|
||||
[gdb-13.2-1-x86_64.pkg.tar.zst.sig](../../_resources/gdb-13.2-1-x86_64.pkg.tar.zst.sig)
|
||||
|
||||
|
||||
|
||||
[gdb-common-13.2-1-x86_64.pkg.tar.zst](../../_resources/gdb-common-13.2-1-x86_64.pkg.tar.zst)
|
||||
|
||||
|
||||
|
||||
[gdb-common-13.2-1-x86_64.pkg.tar.zst.sig](../../_resources/gdb-common-13.2-1-x86_64.pkg.tar.zst.sig)
|
||||
|
||||
|
||||
|
||||
[source-highlight-3.1.9-11-x86_64.pkg.tar.zst](../../_resources/source-highlight-3.1.9-11-x86_64.pkg.tar.zst)
|
||||
|
||||
|
||||
|
||||
[source-highlight-3.1.9-11-x86_64.pkg.tar.zst.sig](../../_resources/source-highlight-3.1.9-11-x86_64.pkg.tar.zst.sig)
|
||||
|
||||
|
||||
|
||||
2. Nodejs
|
||||
|
||||
|
||||
[node-gyp-9.4.0-1-any.pkg.tar.zst](../../_resources/node-gyp-9.4.0-1-any.pkg.tar.zst)
|
||||
|
||||
|
||||
|
||||
[node-gyp-9.4.0-1-any.pkg.tar.zst.sig](../../_resources/node-gyp-9.4.0-1-any.pkg.tar.zst.sig)
|
||||
|
||||
|
||||
|
||||
[nodejs-20.8.0-1-x86_64.pkg.tar.zst](../../_resources/nodejs-20.8.0-1-x86_64.pkg.tar.zst)
|
||||
|
||||
|
||||
|
||||
[nodejs-20.8.0-1-x86_64.pkg.tar.zst.sig](../../_resources/nodejs-20.8.0-1-x86_64.pkg.tar.zst.sig)
|
||||
|
||||
|
||||
|
||||
[nodejs-nopt-7.2.0-1-any.pkg.tar.zst](../../_resources/nodejs-nopt-7.2.0-1-any.pkg.tar.zst)
|
||||
|
||||
|
||||
|
||||
[nodejs-nopt-7.2.0-1-any.pkg.tar.zst.sig](../../_resources/nodejs-nopt-7.2.0-1-any.pkg.tar.zst.sig)
|
||||
|
||||
|
||||
|
||||
[npm-10.2.0-1-any.pkg.tar.zst](../../_resources/npm-10.2.0-1-any.pkg.tar.zst)
|
||||
|
||||
|
||||
|
||||
[npm-10.2.0-1-any.pkg.tar.zst.sig](../../_resources/npm-10.2.0-1-any.pkg.tar.zst.sig)
|
||||
|
||||
|
||||
3. bleachbit
|
||||
|
||||
|
||||
[bleachbit-4.4.2-4-any.pkg.tar.zst](../../_resources/bleachbit-4.4.2-4-any.pkg.tar.zst)
|
||||
|
||||
|
||||
|
||||
[bleachbit-4.4.2-4-any.pkg.tar.zst.sig](../../_resources/bleachbit-4.4.2-4-any.pkg.tar.zst.sig)
|
||||
|
||||
4. SimpleScreenRecorder
|
||||
|
||||
Li
|
||||
[simplescreenrecorder-0.4.4-2-x86_64.pkg.tar.zst](../../_resources/simplescreenrecorder-0.4.4-2-x86_64.pkg.tar.zst)
|
||||
|
||||
5. ProtonVpn
|
||||
|
||||
|
||||
[protonvpn-1.0.0-3-any.pkg.tar.zst](../../_resources/protonvpn-1.0.0-3-any.pkg.tar.zst)
|
||||
|
||||
|
||||
|
||||
[protonvpn-cli-3.13.0-2-any.pkg.tar.zst](../../_resources/protonvpn-cli-3.13.0-2-any.pkg.tar.zst)
|
||||
|
||||
|
||||
|
||||
[protonvpn-gui-1.12.0-1-any.pkg.tar.zst](../../_resources/protonvpn-gui-1.12.0-1-any.pkg.tar.zst)
|
||||
6. Redis
|
||||
|
||||
|
||||
[redis-7.2.1-1-x86_64.pkg.tar.zst](../../_resources/redis-7.2.1-1-x86_64.pkg.tar.zst)
|
||||
|
||||
|
||||
|
||||
[redis-7.2.1-1-x86_64.pkg.tar.zst.sig](../../_resources/redis-7.2.1-1-x86_64.pkg.tar.zst.sig)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
13
joplin notion extension/manjaro/precaching.md
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
precaching
|
||||
|
||||
- https://wiki.archlinux.org/title/Preload
|
||||
Install `gopreload-git` from aur
|
||||
Take ownership of /usr/share/gopreload/enabled and `/usr/share/gopreload/disabled`
|
||||
`chown username:users /usr/share/gopreload/enabled /usr/share/gopreload/disabled
|
||||
`
|
||||
replace username with yours. no need to change group to wheel or what. `users` itself is fine.
|
||||
Then finally use this to make the program launch at boot
|
||||
`gopreload-prepare program`
|
||||
To load all lists at boot, enable the systemd service file gopreload.service.
|
||||
`systemctl enable gopreload.service`
|
||||
|
||||
39
joplin notion extension/manjaro/qemu.md
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
qemu
|
||||
|
||||
From version 7.0.0 of qemu it is split into 3 ie qemu-base,qemu-desktop and qemu-full. Install qemu-desktop for better graphics support in VM.
|
||||
|
||||
- Installation
|
||||
To check if virtualization is supported
|
||||
`LC_ALL=C lscpu | grep Virtualization`
|
||||
*Virtualization: AMD-V*
|
||||
If this is output then yes it's supported
|
||||
|
||||
`egrep -c '(vmx|svm)' /proc/cpuinfo`
|
||||
To check number of cores. If the output is 0 then virtualization is needed to be enabled from bios
|
||||
|
||||
Install these packages
|
||||
`pacman -S qemu virt-manager virt-viewer dnsmasq vde2 bridge-utils openbsd-netcat `
|
||||
for extra install this
|
||||
`pacman -S libguestfs`
|
||||
|
||||
- Starting
|
||||
To start **libvirtd** service
|
||||
`sudo systemctl start libvirtd`
|
||||
To add it in default runtime
|
||||
`sudo systemctl enable libvirtd`
|
||||
|
||||
- Editing libvirtd.conf file
|
||||
`sudo nano /etc/libvirt/libvirtd.conf`
|
||||
Then make sure that
|
||||
`unix_sock_group = "libvirt"`
|
||||
`unix_sock_ro_perms = "0777"`
|
||||
`unix_sock_rw_perms = "0770"`
|
||||
- Adding ourself to libvert group
|
||||
`sudo usermod -aG libvirt hpm`
|
||||
Then restart libvirtd
|
||||
`sudo systemctl restart libvirtd`
|
||||
- If issue is not able t install logd and enable it by
|
||||
`systemctl enable virtlogd`
|
||||
`systemctl start virtlogd`
|
||||
|
||||
|
||||
70
joplin notion extension/manjaro/todo installations.md
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
- [x] Redis
|
||||
- [x] mysql
|
||||
- [x] Docker
|
||||
- [x] codelite
|
||||
- [x] rust
|
||||
- [x] proton vpn
|
||||
- [x] windscribe vpn
|
||||
- [x] balena etcher : for bootable usb
|
||||
- [x] qemu or virtualBox or Vmware
|
||||
- [ ] zoom
|
||||
- [ ] mullwad
|
||||
- [x] tor
|
||||
- [x] qbittorrent
|
||||
- [x] Padloc
|
||||
- [x] Joplin
|
||||
- [x] Librewolf
|
||||
- [x] Floorp
|
||||
- [x] nodejs
|
||||
- [x] stacer
|
||||
- [x] sublime text
|
||||
- [x] vscodium with marketplace
|
||||
- [x] gdb
|
||||
- [x] pip
|
||||
- [x] openjdk 11
|
||||
- [x] yay
|
||||
- [x] Brave
|
||||
- [x] nordvpn
|
||||
- [x] strawberry music player qt5
|
||||
- [x] nvm
|
||||
- [x] base-devel : collection of tools for building packages
|
||||
- [x] Disk usage analyzer (baobab)
|
||||
- [x] Libreoffice
|
||||
- [x] Simple screen recorder
|
||||
- [x] File shredder(raider)
|
||||
- [x] Feem
|
||||
- [x] XDM
|
||||
- [x] Thorium
|
||||
- [x] VLC
|
||||
- [x] Haruna media player
|
||||
- [x] htop
|
||||
- [x] radeontop
|
||||
- [x] iotop
|
||||
- [x] glances
|
||||
- [x] neofetch
|
||||
- [x] tlp
|
||||
- [x] ffmpeg
|
||||
- [x] youtube-dl
|
||||
- [x] wine
|
||||
- [x] android emulator
|
||||
- [x] kde connect
|
||||
- [x] okular(Document viewer)
|
||||
- [x] audacity
|
||||
- [x] Drawing (Doodling with images)
|
||||
- [x] gparted
|
||||
- [x] keypass
|
||||
- [x] marktext (makdown editor and previewer)
|
||||
- [x] localsend
|
||||
- [x] btop (awesome task manager and info about partitions)
|
||||
- [x] d
|
||||
- [x] signal
|
||||
- [x] vivaldi
|
||||
- [x] neovim
|
||||
- [x] timeshift
|
||||
- [x] waterfox
|
||||
- [x] terminator
|
||||
- [x] cmus
|
||||
- [x] engrampa archive manager
|
||||
- [x] liketaskmanager (like windows 10)
|
||||
- [x] p7zip
|
||||
- [x] ark
|
||||
23
joplin notion extension/manjaro/yay installation.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
yay installation
|
||||
|
||||
https://itsfoss.com/install-yay-arch-linux/
|
||||
https://github.com/Jguer/yay
|
||||
|
||||
- Updating system and refreshing package cache
|
||||
`sudo pacman -Syu`
|
||||
- Installing build tools and git
|
||||
`sudo pacman -S --needed base-devel git`
|
||||
`--needed` is useful to not reinstall already installed packages
|
||||
- Building yay
|
||||
`git clone https://aur.archlinux.org/yay.git`
|
||||
`cd yay`
|
||||
`makepkg -si`
|
||||
|
||||
|
||||
- If u dont wanna build then
|
||||
```bash
|
||||
git clone https://aur.archlinux.org/yay-bin.git
|
||||
cd yay-bin
|
||||
makepkg -si
|
||||
```
|
||||
|
||||