Object Oriented Programming Notes(C++)
Difference between en28 and en29, changed 2 character(s)
OOPs are actually very simple but we can have some difficult questions on OOPs as well. We will first have short notes of theory(which can be asked in form of questions) and then shift to questions.↵

I am refering E balaguruswamy book for this. These are short notes and may miss something, if you think something is missing please comment. Also, we would be using this track:↵

1. Introduction to classes and objects↵
2. Constructors and Destructors↵
3. Operator Overloading↵
4. Inheritance↵
5. Polymorphism↵

> We will be discussing major topics here and actually difficult ones. **You must know basic OOPs**.↵

### Introduction↵

<spoiler summary="C structures Vs C++ Classes">↵
We know structures can be used to create user-defined data types in C and C++. But then why we need classes? We can have functions, constructors, etc in structures as well but what differentiates it from classes are lack of abstraction and inheritance(And actually many other things as well). We can hide certain members from outside world(abstraction) in a class but we can't do anything like this in structures. Also, we cannot overload an operator here(operator overloading is not permissible on structs in C language, although it's possible in C++). For example↵

~~~~~↵
struct complex{↵
    float x,y;↵
};↵
// Structure for a complex number of form x+iy(i stands for iota)↵
complex c1,c2;↵
c1.x=1;↵
c1.y=2;↵
c2.x=3;↵
c2.y=3;↵
// c1=1+2i, c2=3+3i↵
complex c3=c1+c2;//Illegal statement in C because we cannot add these two structures. ↵
~~~~~↵
</spoiler>↵

<spoiler summary="General structure of classes">↵
~~~~~↵
class className{↵
   private:↵
       variable declaration;↵
       function declaration;↵
   public:↵
       variable declaration;↵
       function declaration;↵
};↵
~~~~~↵
</spoiler>↵

<spoiler summary="Visibility labels(Public, private, protected">↵
1. **private**: Data members labelled private are only available withing the class.↵
2. **public**: Data members are available for the outside world as well.↵
3. **protected**: Data members are not available for the whole world but are available to the inherited classes.↵

> By default, all members are private. ↵
</spoiler>↵

<spoiler summary="Some terms and their meaning">↵

1. **Abstraction**: Data hiding. All those visibility labels are used for abstraction only. We can achieve data hiding using the visibility labels(private)↵
2. **Encapsulation**: Data binding. This is just binding various data members and functions into a class. We actually do that, so it's kind of default behaviour.↵
3. **Polymorphism**:↵
4. **Inheritance**:↵
5. **Overloading**:↵

</spoiler>↵


<spoiler summary="For CP lovers, here is class based implementation of segment trees and Euler tours, representing inheritance as well(although we don't actually need inheritance here)">↵
Question Link: https://cses.fi/problemset/task/1138↵

~~~~~↵
#include<bits/stdc++.h>↵
using namespace std;↵
#define int long long int↵
const int mxN = 200001;↵
int inf = 1e18;↵
class segTree↵
{↵
private:↵
    vector<int>tree;↵
    vector<int>a;↵
    void buildTree(int i, int st, int end, vector<int> &arr)↵
    {↵
        if(st == end)↵
        {↵
            tree[i] = arr[st];↵
            return;↵
        }↵
 ↵
        int mid = st + (end - st) / 2;↵
        int lchild = 2 * i + 1;↵
        int rchild = 2 * i + 2;↵
 ↵
        buildTree(lchild, st, mid, arr);↵
 ↵
        buildTree(rchild, mid + 1, end, arr);↵
 ↵
        tree[i] = tree[lchild] + tree[rchild];↵
    }↵
    int queryPrivate(int i, int segStart, int segEnd, int l, int r)↵
    {↵
        if(segEnd < l || segStart > r)return 0;↵
 ↵
        if(segEnd <= r && segStart >= l)↵
            return tree[i];↵
 ↵
        int lchild = 2 * i + 1;↵
        int rchild = 2 * i + 2;↵
 ↵
        int mid = segStart + (segEnd - segStart) / 2;↵
 ↵
        int resL = queryPrivate(lchild, segStart, mid, l, r);↵
        int resR = queryPrivate(rchild, mid + 1, segEnd, l, r);↵
 ↵
        return resL + resR;↵
    }↵
    void upd(int i, int st, int end, int ind, int newVal)↵
    {↵
        if(st == end)↵
        {↵
            tree[i] = newVal;↵
            return;↵
        }↵
 ↵
        int mid = st + (end - st) / 2;↵
 ↵
        if(ind <= mid)↵
            upd(2 * i + 1, st, mid, ind, newVal);↵
        else↵
            upd(2 * i + 2, mid + 1, end, ind, newVal);↵
 ↵
        tree[i] = tree[2 * i + 1] + tree[2 * i + 2];↵
    }↵
public:↵
    void build(vector<int> &arr)↵
    {↵
        int n = arr.size();↵
        tree.resize(4 * n + 1);↵
        for(int i = 0; i < 4 * n + 1; i++)tree[i] = inf;↵
        buildTree(0, 0, n &mdash; 1, arr);↵
        a = arr;↵
    }↵
    int queryTree(int l, int r)↵
    {↵
        int n = a.size();↵
        return queryPrivate(0, 0, n &mdash; 1, l, r);↵
    }↵
 ↵
    void updateTree(int indToChange, int newVal)↵
    {↵
        int n = a.size();↵
        upd(0, 0, n - 1, indToChange, newVal);↵
    }↵
};↵
// Inherited segTree class to Tree class↵
class Tree : public segTree↵
{↵
    vector<int>adj[mxN];↵
    vector<int>val;↵
    vector<int>in;↵
    vector<int>out;↵
    vector<int>eTour;↵
    segTree s;↵
public:↵
    Tree(vector<int>arr)↵
    {↵
        // cout<<"u";↵
        int n = arr.size();↵
        val.resize(n);↵
        in.resize(n);↵
        out.resize(n);↵
        for(int i = 0; i < n; i++)in[i] = -1;↵
        for(int i = 0; i < n; i++)out[i] = -1;↵
        val = arr;↵
    }↵
    void dfs(int src, vector<bool> &vis)↵
    {↵
        vis[src] = 1;↵
        eTour.push_back(src);↵
        for(auto it : adj[src])↵
        {↵
            if(!vis[it])↵
                dfs(it, vis);↵
        }↵
        eTour.push_back(src);↵
    }↵
    void eulerTour()↵
    {↵
        vector<bool>vis(val.size());↵
        dfs(0, vis);↵
        for(int i = 0; i < eTour.size(); i++)↵
        {↵
            if(in[eTour[i]] == -1)↵
                in[eTour[i]] = i;↵
            else↵
                out[eTour[i]] = i;↵
        }↵
        for(int i = 0; i < eTour.size(); i++)↵
        {↵
            if(in[eTour[i]]==i)↵
                eTour[i] = val[eTour[i]];↵
            else↵
                eTour[i] = -val[eTour[i]];↵
            // cout<<eTour[i]<<" ";↵
        }↵
        // cout<<"\n";↵
        build(eTour);↵
    }↵
    void addEdge(int x, int y)↵
    {↵
        adj[x &mdash; 1].push_back(y &mdash; 1);↵
        adj[y &mdash; 1].push_back(x &mdash; 1);↵
    }↵
    int query(int node)↵
    {↵
        node--;↵
        return queryTree(0, in[node]);↵
    }↵
    void update(int node, int x)↵
    {↵
        node--;↵
        updateTree(in[node], x);↵
        updateTree(out[node], -x);↵
        val[node] = x;↵
    }↵
};↵
int32_t main()↵
{↵
    // This is the holy code of the demon AB-DUDE↵
    // This is the code of the question : https://cses.fi/problemset/task/1137/↵
    // We used Euler Tour and Segment Trees for this↵
    // Just do a Euler tour of type 2 on the tree and make a basic segment tree on the array↵
    // Now, we can just use in and out arrays for the positions of the nodes in the euler tour array↵
 ↵
    int n, q;↵
    cin >> n >> q;↵
    vector<int>a(n);↵
    for(int i = 0; i < n; i++)cin >> a[i];↵
 ↵
    Tree tr(a);↵
    for (int i = 0; i < n - 1; ++i)↵
    {↵
        int x, y;↵
        cin >> x >> y;↵
        tr.addEdge(x, y);↵
    }↵
    tr.eulerTour();↵
    for(int i = 0; i < q; i++)↵
    {↵
        int t;↵
        cin >> t;↵
        if(t == 1)↵
        {↵
            int s, x;↵
            cin >> s >> x;↵
            tr.update(s, x);↵
        }↵
        else↵
        {↵
            int s;↵
            cin >> s;↵
            cout << tr.query(s) << "\n";↵
        }↵
    }↵
 ↵
    return 0;↵
}↵
~~~~~↵
</spoiler>↵


<spoiler summary="Memory allocation of member variables and functions accross objects"> ↵
![alt text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/frkirfhdunkx3lmxuc5e.png)↵

Member variables are different for different objects but member functions are the same, which is quite obvious.↵
</spoiler>↵

**Static Data members**↵

As we saw in memory allocation diagram, copies of member variables are made for different objects. But if we want a common variable for all objects of class? For example in an employee class, we need to find the number of employees at a specific time. We can do it using a global variable but that variable can interfere in the whole working of program. We can use a **static data member**. Static members are initialized to 0 and one important thing to note is that type and scope of static variable is defined outside the class. This is because they are not of every object but are unique to a class. And where we have variables, we do have functions also. **Static member functions** are also specific to a class, and can access only static members. Please have a code for implementation of both(Here I have kept the static member function outside to generalize the concept that static members are specific to class but they can be defined and implemented inside the class as well)↵

<spoiler summary="Sample Code for static data members">↵
~~~~~↵
#include<bits/stdc++.h>↵
using namespace std;↵
#define int long long int↵
class Customers{↵
    static int customer_count;↵
    vector<string> movies;↵
public:↵
    static void showCount();↵
    Customers()↵
    {↵
        customer_count++;↵
    }↵
    void addMovie(string s)↵
    {↵
        movies.push_back(s);↵
    }↵
};↵
int Customers::customer_count;↵
void Customers::showCount()↵
{↵
    cout<<customer_count<<"\n";↵
}↵
int32_t main()↵
{↵

    Customers C1;↵
    Customers C2;↵
    C1.addMovie("Shawshank Redemption");↵
    C2.addMovie("Ananda");↵
    C2.addMovie("Bhootnath");↵
    C2.addMovie("Hera Pheri");↵
    C2.addMovie("Phir Hera Pheri");↵
    C2.addMovie("Welcome");↵
    C2.addMovie("Golmaal");↵
    C1.addMovie("Avengers: Infinity Wars");↵
    C1.addMovie("Avengers: Endgame");↵
    C1.addMovie("Deadpool");↵
    C1.addMovie("Godfather");↵

    Customers::showCount();↵
    return 0;↵
}↵
~~~~~↵
</spoiler>↵

All other operations like making an array, vector, or any other STL container works the same for classes(Although you have to make a custom comparator in case of sorting through STL) remains almost same. We can also pass objects as arguments which is self explanatory. ↵

**Friendly Functions**↵

There can be a case when we want some function to access private members of a class. For example, suppose there are two classes, Software engineers and Software testers. We want to find maximum income between both of the classes(Although many testers may not be eligible to pay taxes in India(Minimum salary is 5LPA for tax payers)). But we don't want to use the private member "income" as we can't access private members using objects directly. So, what we do is we make a friend function which can access private members of both the classes outside of both of them. This way, it can access both the classes without actually being a part of the class. (Obviously, we have to define that a particular function is friend inside the class as it would be a security threat if any function can be friend)↵

<spoiler summary="Code for Friend Functions">↵
~~~~~↵
#include<bits/stdc++.h>↵
using namespace std;↵
#define int long long int↵
class SofTesters;↵
class SofEngineers{↵
public:↵
    int income=1000;↵
    friend int greaterIncome(SofEngineers, SofTesters);↵
    void copyCode()↵
    {↵
        cout<<"The deadline is too short!!\n";↵
    }↵
    void pasteCode()↵
    {↵
        cout<<"Why the f it's not working!!!\n";↵
    }↵
};↵
class SofTesters{↵
public:↵
    int income=10;↵
    friend int greaterIncome(SofEngineers, SofTesters);↵
    void curseDev()↵
    {↵
        cout<<"That dev is a dumba**, 5 test scripts failed!";↵
    }↵
    void appologize()↵
    {↵
        cout<<"Oh shoot, Too much work, that intern made a mistake in making test scripts.";↵
    }↵
};↵

int greaterIncome(SofEngineers a, SofTesters b)↵
{↵
    return a.income>=b.income;↵
}↵

int32_t main()↵
{↵
    SofEngineers abdude;↵
    SofTesters lord_invincible;↵
    cout<<greaterIncome(abdude,lord_invincible);↵
    return 0;↵
}↵
~~~~~↵
</spoiler>↵

> If a member function do not alter any data, we put a const ahead of its definition: `void changeNothing() const;`↵

**Pointers to members of a class**↵

Suppose this is the class:↵

~~~~~↵
class A{↵
private:↵
    int x;↵
};↵
~~~~~↵

We define a pointer to X as:↵
`int A ::* it=&A :: m;`↵

Now, it contains address of m and we can refer to m using *it.↵

## Constructors and Destructors↵

**Constructor**↵

Special member functions having the same name as the class used to initialize objects. Whenever a new object is created, this member function is called. ↵

<spoiler summary="Constructor example in segment tree implementation">↵
~~~~~↵
class segTree{↵
private:↵
    vector<int>tree;↵
    vector<int>a;↵
    void buildTree(int i,int st,int end,vector<int>&arr)↵
    {↵
        if(st==end){↵
            tree[i]=arr[st];↵
            return;↵
        }↵
        ↵
        int mid=st+(end-st)/2;↵
        int lchild=2*i+1;↵
        int rchild=2*i+2;↵
        ↵
        buildTree(lchild,st,mid,arr);↵
        ↵
        buildTree(rchild,mid+1,end,arr);↵
 ↵
        tree[i]=tree[lchild]+tree[rchild];↵
    }↵
    int queryPrivate(int i,int segStart,int segEnd,int l,int r)↵
    {↵
        if(segEnd<l||segStart>r)return 0;↵
        ↵
        if(segEnd<=r&&segStart>=l)↵
            return tree[i];↵
        ↵
        int lchild=2*i+1;↵
        int rchild=2*i+2;↵
        ↵
        int mid=segStart+(segEnd-segStart)/2;↵
 ↵
        int resL=queryPrivate(lchild,segStart,mid,l,r);↵
        int resR=queryPrivate(rchild,mid+1,segEnd,l,r);↵
 ↵
        return resL+resR;↵
    }↵
    void upd(int i,int st,int end,int ind,int newVal)↵
    {↵
        if(st==end)↵
        {↵
            tree[i]=newVal;↵
            return;↵
        }↵
        ↵
        int mid=st+(end-st)/2;↵
        ↵
        if(ind<=mid)↵
            upd(2*i+1,st,mid,ind,newVal);↵
        else↵
            upd(2*i+2,mid+1,end,ind,newVal);↵
        ↵
        tree[i]=tree[2*i+1]+tree[2*i+2];↵
    }↵
public:↵
// Constructor here↵
    segTree(vector<int>&arr)↵
    {↵
        int n=arr.size();↵
        tree.resize(4*n+1);↵
        for(int i=0;i<4*n+1;i++)tree[i]=inf;↵
        buildTree(0,0,n-1,arr);↵
        a=arr;↵
    }↵
    int query(int l,int r)↵
    {↵
        int n=a.size();↵
        return queryPrivate(0,0,n-1,l,r);↵
    }↵
    ↵
    void update(int indToChange,int newVal){↵
        int n=a.size();↵
        upd(0,0,n-1,indToChange,newVal);↵
    }   ↵
};↵
~~~~~↵
</spoiler>↵

Constructors can be parametrized or without any parameters as well. Constructors without any parameters are **default constructors**. Please note that if a parameterized constructor is present and no default constructor is present, this type of initialization will give you an error: `segTree s;` because compiler couldn't find any default constructor. But if no constructor is present, compiler supplies one.↵

<spoiler summary="Some properties of constructors:">↵
1. Always in public section↵
2. No return type↵
3. Cannot be inherited↵
4. Constructors cannot be **virtual**.↵
</spoiler>↵

The parameters of a constructor can be of any type except for that class only but it can accept a reference to the class. These constructors are called **copy constructors**. Copy Constructors can be used to create two objects with same member variables.↵

<spoiler summary="Example of Copy Constructors">↵
~~~~~↵
class A{↵
public:↵
    A(A&){↵

    }↵
};↵
~~~~~↵
</spoiler>↵

We can also use constructors dynamically. That is, we can use them after initialization of objects also. ↵

<spoiler summary="Code for Dynamic Initialization of Objects">↵
~~~~~↵
#include<bits/stdc++.h>↵
using namespace std;↵

class Problem{↵
    int diff;↵
    string name="";↵
public:↵
    Problem(){};↵
    Problem(int diff)↵
    {↵
        this->diff=diff;↵
    }↵
    Problem(int diff,string name)↵
    {↵
        this->diff=diff;↵
        this->name=name;↵
    }↵
    void display()↵
    {↵
        cout<<"Problem Name is "<<name<<endl;↵
        cout<<"Problem Difficult is "<<diff<<endl;↵
    }↵
};↵
int main()↵
{↵
    Problem P1,P2,P3;↵
    // After initialization↵
    P1 = Problem(1000);↵
    P2 = Problem(1200,"Nasya And Array");↵
    P3 = Problem(2100,"Nasya And Tree");↵
    P1.display();↵
    P2.display();↵
    P3.display();↵
}↵
~~~~~↵
</spoiler>↵

**Destructors**↵

A destructor, as name suggests, is used to delete objects that have been created by a constructor. As we saw in memory allocation, each object has its own memory for its member variables. Suppose we have a vector and we are resizing it inside the constructor. Then we should use a destructor as well to free that memory. (Not in general, but in big firms, yes its necessary)↵

<spoiler summary="Destructor Example">↵
~~~~~↵
#include<bits/stdc++.h>↵
using namespace std;↵

class Problem{↵
    vector<int>problemRatings;↵
public:↵
    Problem(){};↵
    Problem(int diff)↵
    {↵
        problemRatings.resize(diff);↵
    }↵
//Destructor:↵
    ~Problem,2021-08-20()↵
    {↵
        problemRatings.clear();↵
    }↵
};↵
int main()↵
{↵
    Problem P1(1000);↵
}↵
~~~~~↵
</spoiler>↵

## Operator Overloading↵

This is perhaps the most interesting part of OOPs. As we saw initially, we can't do a (+) operation on structures, but we can do it in classes using operator overloading. For example, we can use a (+) operator for strings to concatenate them in C++. Similarly, we can modify the meaning of an operator for a class. The possibilities with this are immense. Just imagine, you can actually add maps, sets according to the meaning interpreted by you. You can practically create your own language with this feature. But there are some operators you can't overload.↵

<spoiler summary="List of operators you can't overload">↵
1. Class member access operators( (.) , (*))↵
2. Scope resolution operator( :: )↵
3. Size operator(sizeof)↵
4. Conditional operator (?)↵
</spoiler>↵

> Please note that the precedence of the operators don't change. Multiplication will have a higher precedence than addition. ↵

**Let's Overload some Unary and Binary Operators!**↵

1. Unary Operator:↵

<spoiler summary="Example of Unary operator, in a class complex, which is like an actual complex number">↵
Complex Number of form $ a + i*b $↵

~~~~~↵
#include<bits/stdc++.h>↵
using namespace std;↵
#define int long long int↵
class Complex{↵
    int real,im;↵
public:↵
    Complex(){}↵
    Complex(int r=0,int i=0)↵
    {↵
        real=r;↵
        im=i;↵
    }↵
    //Overloading Unary Operator↵
    void operator-()↵
    {↵
        real=-real;↵
        im=-im;↵
    }↵
    // Overloading insertion operator;↵
    friend ostream& operator<<(ostream& os, const Complex& a);↵
};↵
ostream& operator<<(ostream& os, const Complex& a)↵
{↵
    os<<a.real<<" + i"<<a.im<<endl;↵
    return os;↵
}↵
int32_t main()↵
{↵
    Complex C1(10,-2);↵
    // 10+2i↵
    // -C1=-10+2i;↵
    // We overloaded the insertion operator as well!↵
    cout<<C1;↵
    // Please Note that we are not doing, C=-C, because we are not returning anything in our implementation.↵
    -C1;↵
    cout<<C1;↵
    return 0;↵
}↵
~~~~~↵

Please note that while overloading "<<" operator, we declared our function as a friend function. This is because if operator is overloaded as a member, it must be a member of the object on the left of the operator. Now, instead of including it inside the istream class of C++, we declare it globally and make it a friend function.↵
</spoiler>↵

Now, you might be having a feel how all the STL containers are made. And that's why OOPs are hell awesome!↵

Now let's overload a binary operator. ↵

<spoiler summary="Overloading subtraction operator">↵
~~~~~↵
#include<bits/stdc++.h>↵
using namespace std;↵
#define int long long int↵
class Complex{↵
    int real,im;↵
public:↵
    Complex(){}↵
    Complex(int r,int i)↵
    {↵
        real=r;↵
        im=i;↵
    }↵
    // Overloading Unary Operator↵
    void operator-()↵
    {↵
        real=-real;↵
        im=-im;↵
    }↵
    // Overloading binary Operator↵
    Complex operator+(Complex a)↵
    {↵
        Complex C;↵
        C.im=im+a.im;↵
        C.real=real+a.real;↵
        return C;↵
    }↵
    // Overloading binary Operator↵
    Complex operator-(Complex a)↵
    {↵
        Complex C;↵
        C.im=im-a.im;↵
        C.real=real-a.real;↵
        return C;↵
    }↵
    // Overloading insertion operator;↵
    friend ostream& operator<<(ostream& os, const Complex& a);↵
};↵
ostream& operator<<(ostream& os, const Complex& a)↵
{↵
    os<<a.real<<" + "<<a.im<<"i"<<endl;↵
    return os;↵
}↵

int32_t main()↵
{↵
    Complex C1(10,-2),C2(20,5),C11(1,-1);↵
    Complex C3=C1+C2+C11;   ↵
    Complex C4=C1-C2+C11;↵
    cout<<C3;↵
    cout<<C4;↵
    return 0;↵
}↵
~~~~~↵
</spoiler>↵

Left hand operand is used to invoke the operator and right hand operand is passed as an argument.↵

<spoiler summary="Diagram representing the operator overloading process">↵
![alt text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/44evkkqid3k1u2o6r8p5.png)↵
</spoiler>↵

As we used a friend function in dealing with "<<" operator, we have to use a friend member for dealing with any operator in which any one operator is not of the same type.↵

**Type Conversion**↵

We all know type conversions very well (Assuming you are familiar with C++). We use type conversions to convert a double to int, or a character to integer. Although it's not extreme necessary, but it saves some time. These are the three cases we can have : ↵

1. Basic to User defined class.↵
2. User defined class to Basic↵
3. User defined to another user defined↵

To be updated↵

## Inheritance↵

Here comes the interesting part of OOPs. With this we can actually support reusability. It's quite easy to understand as well.↵

<spoiler summary="1. Types of Inheritance">↵
To be updated↵
</spoiler>↵

 ↵

<spoiler summary="2. Access modifiers in Inheritance">↵
To be updated↵
</spoiler>↵

<spoiler summary="3. Ambiguities in Inheritance">↵
To be updated↵
</spoiler>↵

<spoiler summary="4. Virtual base classes and their applications">↵
To be updated↵
</spoiler>↵


<spoiler summary="5. Abstract classes and real life application">↵
To be updated↵
</spoiler>↵

<spoiler summary="6. Nesting classes">↵
To be updated↵
</spoiler>↵



If you want to see the real life application of inheritance, see this code snippet and working here(links would be attached soon). (It was made by me so, maybe a bit clumsy at first look, but see the working, it's my new project(The full project will be uploaded soon))↵



## Polymorphism↵

To be updated

History

 
 
 
 
Revisions
 
 
  Rev. Lang. By When Δ Comment
en29 English abdude824 2022-08-10 12:46:07 2 (published)
en28 English abdude824 2022-08-10 12:45:45 64 Reverted to en26
en27 English abdude824 2022-07-21 14:19:23 64 (saved to drafts)
en26 English abdude824 2021-09-20 10:08:43 950
en25 English abdude824 2021-08-25 12:30:52 97
en24 English abdude824 2021-08-22 17:51:00 369
en23 English abdude824 2021-08-21 09:49:20 38 Tiny change: ' type.\n\n\n## Inh' -> ' type.\n\n**Type Conversion**\n\nTo be updated\n\n## Inh' (published)
en22 English abdude824 2021-08-20 21:07:00 480
en21 English abdude824 2021-08-20 19:56:08 1363
en20 English abdude824 2021-08-20 19:41:14 467
en19 English abdude824 2021-08-20 19:34:03 1012 Tiny change: ' form a+$i%b">\n\n</s' -> ' form a+$i$b">\n\n</s'
en18 English abdude824 2021-08-20 17:44:31 2 Tiny change: ' would be suing this t' -> ' would be using this t'
en17 English abdude824 2021-08-20 15:20:16 126
en16 English abdude824 2021-08-20 13:19:28 16
en15 English abdude824 2021-08-20 13:17:47 762
en14 English abdude824 2021-08-20 12:51:38 764
en13 English abdude824 2021-08-20 12:36:39 103
en12 English abdude824 2021-08-20 12:29:44 1758
en11 English abdude824 2021-08-20 11:57:34 2049
en10 English abdude824 2021-08-20 11:43:02 130
en9 English abdude824 2021-08-19 22:32:45 907
en8 English abdude824 2021-08-19 21:26:19 2653
en7 English abdude824 2021-08-19 20:57:41 1054
en6 English abdude824 2021-08-19 15:24:19 3
en5 English abdude824 2021-08-17 21:33:53 894 Tiny change: '/articles/n5kflb4dv5c2koi41uk2.png)\n</' -> '/articles/qnvv0uasstduy2zueqo2.png)\n</'
en4 English abdude824 2021-08-17 10:59:06 4 Tiny change: 'ask/1138\n~~~~~\n#' -> 'ask/1138\n\n~~~~~\n#'
en3 English abdude824 2021-08-17 10:58:45 5290
en2 English abdude824 2021-08-17 10:37:59 559
en1 English abdude824 2021-08-17 10:31:10 1201 Initial revision (saved to drafts)