1 Commits

Author SHA1 Message Date
097af8d222 [cpp] Add example and solution for deadlocks 2022-04-02 11:44:00 -04:00
129 changed files with 287 additions and 10941 deletions

2
.gitignore vendored
View File

@@ -10,5 +10,3 @@
**/Makefile
**/*.cbp
**/node-modules/
**/CMakeLists.txt.user
**/catch2/bin/

View File

@@ -2,16 +2,14 @@
This repository is a collection of useful code snippets and configurations.
```bash
```
github.com/shaunrd0/klips/
├── ansible # Ansible roles, playbooks, and examples
├── blockchain # Blockchain related project templates and examples
├── cpp # C++ programs, datastructures, and other examples
├── dotnet # .NET projects and examples
├── esp # ESP32 projects and examples
├── figlet # Figlet fonts I like :)
├── javascript # Javascript projects and examples
├── python # Python scripts and tools I've made
├── README.md
├── python # Python scripts or tools I've made
├── README.md
└── scripts # Bash scripts
```

View File

@@ -1,4 +1,4 @@
# ansible
# Ansible
A few simple roles / plays I've put together in learning how to use Ansible can be found under their corresponding directories.

View File

@@ -1,4 +1,3 @@
# blockchain
A template project for getting started working on the Ethereum blockchain.
This project comes with basic packages for compiling and deploying Solidity contracts with Truffle.
@@ -73,7 +72,7 @@ I explain how to configure metamask on ropsten on [Knoats - Solidity](https://kn
Give yourself test Ethereum with the [Ropsten ETH Faucet](https://faucet.ropsten.be)
To deploy to ropsten test network, and verify using `truffle-verify-plugin` -
To deploy to ropsten test network, and verify using `truffle-verify-plugin` -
```asm
npx truffle migrate --network ropsten

View File

@@ -21,11 +21,9 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
add_compile_options("-Wall")
add_subdirectory(algorithms)
add_subdirectory(catch2)
add_subdirectory(cmake-example)
add_subdirectory(cryptography)
add_subdirectory(datastructs)
add_subdirectory(graphics)
add_subdirectory(multithreading)
add_subdirectory(patterns)
add_subdirectory(qt)
add_subdirectory(patterns)

View File

@@ -1,23 +1,21 @@
# cpp
# Cpp
```bash
shaunrd0/klips/cpp/
├── algorithms # Examples of various algorithms written in C++
├── cmake # Example of using cmake to build and organize larger projects
├── cryptography # Examples of encrypting / decrypting using ciphers in C++
├── datastructs # Collection of useful datastructures written in C++
├── graphics # Examples of graphics projects written in C++
├── multithreading # Basic multithreading examples in C++
├── patterns # Examples of various design patterns written in C++
├── qt # Qt project examples using C++
├── algorithms # Examples of various algorithms written in C++
├── cmake # Example of using cmake to build and organize larger projects
├── cryptography # Examples of encrypting / decrypting using ciphers in C++
├── datastructs # Collection of useful datastructures written in C++
├── graphics # Examples of graphics projects written in C++
├── patterns # Examples of various design patterns written in C++
└── README.md
```
This directory contains a `CMakeLists.txt`, which can be selected to open as a
This directory contains a `CMakeLists.txt`, which can be selected to open as a
project within your preferred IDE. From there, all nested examples can be built,
debugged, and ran.
Some of the more recent projects in this repository requires the latest CMake LTS.
Some of the more recent projects in this repository requires the latest CMake LTS.
To install `cmake` LTS with `apt` we can follow [official instructions from kitware](https://apt.kitware.com/)
Alternatively, we can install the LTS with python's `pip`.
```bash
@@ -34,7 +32,7 @@ cmake version 3.22.1
Once cmake is installed, dependencies for all examples can be installed with the command below.
```bash
sudo apt install libsdl2-dev freeglut3-dev
sudo apt install libsdl2-dev freeglut3-dev
```
If we build from this directory, we build all C++ projects and examples
@@ -63,7 +61,7 @@ graph-test-object sdl-test visitor-test
graph-test-simple select-sort
```
We can also build from subdirectories.
We can also build from subdirectories.
To only build projects related to design patterns we build from the `patterns/` subdirectory, for example
```bash
cd /path/to/klips/cpp/patterns
@@ -80,5 +78,5 @@ adapter-test factory-test prototype-test state-test
If cmake is not being used in a project, it can be built with `g++` manually using
the commands outlined in `*/.vscode/tasks.json`, or by using VSCode to open the example
and running the build task.
and running the build task.
Check the header comments in the main source file for the example for instructions.

View File

@@ -1,7 +1,8 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Driver program to test object graph implementation ##
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: An example of an object graph implementation ##
## Algorithms in this example are found in MIT Intro to Algorithms ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################

View File

@@ -1,8 +1,7 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: An example of an object graph implementation ##
## Algorithms in this example are found in MIT Intro to Algorithms ##
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: Driver program to test object graph implementation ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
@@ -184,3 +183,4 @@ std::vector<Node> Graph::TopologicalSort(const Node &startNode) const
// + Output is handled in main as FILO, similar to a stack
return order;
}

View File

@@ -1,6 +1,6 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: An example of an object graph implementation ##
## Algorithms in this example are found in MIT Intro to Algorithms ##
## ##
@@ -10,14 +10,51 @@
#ifndef LIB_GRAPH_HPP
#define LIB_GRAPH_HPP
#include <algorithm>
#include <iostream>
#include <algorithm>
#include <map>
#include <queue>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include <queue>
#include <unordered_set>
#include <unordered_map>
/******************************************************************************/
// Structures for tracking information gathered from various traversals
struct Node;
// Color represents the discovery status of any given node
// + White is undiscovered, Gray is in progress, Black is fully discovered
enum Color {White, Gray, Black};
// Information used in all searches
struct SearchInfo {
// Coloring of the nodes is used in both DFS and BFS
Color discovered = White;
};
// Information that is only used in BFS
struct BFS : SearchInfo {
// Used to represent distance from start node
int distance = 0;
// Used to represent the parent node that discovered this node
// + If we use this node as the starting point, this will remain a nullptr
const Node *predecessor = nullptr;
};
// Information that is only used in DFS
struct DFS : SearchInfo {
// Create a pair to track discovery / finish time
// + Discovery time is the iteration the node is first discovered
// + Finish time is the iteration the node has been checked completely
// ++ A finished node has considered all adjacent nodes
std::pair<int, int> discoveryFinish;
};
// Store search information in unordered_maps so we can pass it around easily
// + Allows each node to store relative information on the traversal
using InfoBFS = std::unordered_map<int, struct BFS>;
using InfoDFS = std::unordered_map<int, struct DFS>;
/******************************************************************************/
@@ -26,16 +63,14 @@ struct Node {
public:
// Constructors
Node(const Node &rhs) = default;
Node & operator=(Node rhs)
{
Node & operator=(Node rhs) {
if (this == &rhs) return *this;
swap(*this, rhs);
return *this;
}
Node(int num, std::vector<int> adj) : number(num), adjacent(std::move(adj)) {}
friend void swap(Node &a, Node &b)
{
friend void swap(Node &a, Node &b) {
std::swap(a.number, b.number);
std::swap(a.adjacent, b.adjacent);
}
@@ -50,61 +85,8 @@ public:
};
/******************************************************************************/
// Base struct for storing traversal information on all nodes
// Color represents the discovery status of any given node
enum Color {
// Node is marked as undiscovered
White,
// Node discovery is in progress; Some adjacent nodes have not been checked
Gray,
// Node has been discovered; All adjacent nodes have been checked
Black
};
// Information used in all searches tracked for each node
struct NodeInfo {
// Coloring of the nodes is used in both DFS and BFS
Color discovered = White;
};
/******************************************************************************/
// BFS search information struct
// Node information that is only used in BFS
struct BFS : NodeInfo {
// Used to represent distance from start node
int distance = 0;
// Used to represent the parent node that discovered this node
// + If we use this node as the starting point, this will remain a nullptr
const Node *predecessor = nullptr;
};
// Store search information in unordered_maps so we can pass it around easily
// + Allows each node to store relative information on the traversal
using InfoBFS = std::unordered_map<int, struct BFS>;
/******************************************************************************/
// DFS search information struct
// Node information that is only used in DFS
struct DFS : NodeInfo {
// Create a pair to track discovery / finish time
// + Discovery time is the iteration the node is first discovered
// + Finish time is the iteration the node has been checked completely
// ++ A finished node has considered all adjacent nodes
std::pair<int, int> discoveryFinish;
};
using InfoDFS = std::unordered_map<int, struct DFS>;
/******************************************************************************/
// Graph class declaration
class Graph {
public:
// Constructor
@@ -119,7 +101,7 @@ public:
// An alternate DFS that checks each node of the graph beginning at startNode
InfoDFS DFS(const Node &startNode) const;
// Visit function is used in both versions of DFS
void DFSVisit(int &time, const Node& startNode, InfoDFS &dfs) const;
void DFSVisit(int &time, const Node& startNode, InfoDFS &searchInfo) const;
// Topological sort, using DFS
std::vector<Node> TopologicalSort(const Node &startNode) const;

View File

@@ -1,6 +1,6 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: Driver program to test a simple graph implementation ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##

View File

@@ -1,6 +1,6 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: An example of a simple graph implementation ##
## Algorithms in this example are found in MIT Intro to Algorithms ##
## ##

View File

@@ -1,6 +1,6 @@
/*#############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: An example of a simple graph implementation ##
## Algorithms in this example are found in MIT Intro to Algorithms ##
## ##
@@ -12,9 +12,9 @@
#include <iostream>
#include <queue>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <vector>
class Graph {

View File

@@ -1,7 +1,7 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Driver program to test templated object graph implementation ##
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: An example of a weighted graph implementation ##
## Algorithms in this example are found in MIT Intro to Algorithms ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##

View File

@@ -1,7 +1,7 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: An example of a templated object graph implementation ##
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: An example of an object graph implementation ##
## Algorithms in this example are found in MIT Intro to Algorithms ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
@@ -10,88 +10,38 @@
#ifndef LIB_GRAPH_HPP
#define LIB_GRAPH_HPP
#include <algorithm>
#include <iostream>
#include <algorithm>
#include <map>
#include <queue>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
/******************************************************************************/
// Node structure for representing a graph
template <typename T>
struct Node {
public:
template <typename> friend class Graph;
template <typename> friend class InfoMST;
// Constructors
Node(const Node &rhs) = default;
Node & operator=(Node rhs)
{
if (this == &rhs) return *this;
swap(*this, rhs);
return *this;
}
Node(T data, const std::vector<std::pair<T, int>> &adj) : data_(data)
{
// Place each adjacent node in vector into our unordered_map of edges
for (const auto &i : adj) adjacent_.emplace(i.first, i.second);
}
friend void swap(Node &a, Node &b)
{
std::swap(a.data_, b.data_);
std::swap(a.adjacent_, b.adjacent_);
}
// Operators
// Define operator== for std::find; And comparisons between nodes
bool operator==(const Node<T> &b) const { return this->data_ == b.data_;}
// Define an operator!= for comparing nodes for inequality
bool operator!=(const Node<T> &b) const { return this->data_ != b.data_;}
// Accessors
inline T GetData() const { return data_;}
inline std::unordered_map<int, int> GetAdjacent() const { return adjacent_;}
private:
T data_;
// Adjacent stored in an unordered_map<adj.number, edgeWeight>
std::unordered_map<T, int> adjacent_;
};
#include <queue>
#include <unordered_set>
#include <unordered_map>
/******************************************************************************/
// Base struct for storing traversal information on all nodes
// Color represents the discovery status of any given node
enum Color {
// Node is marked as undiscovered
White,
// Node discovery is in progress; Some adjacent nodes have not been checked
Gray,
// Node has been discovered; All adjacent nodes have been checked
Black
};
template <typename T> struct Node;
// Information used in all searches tracked for each node
struct NodeInfo {
// Color represents the discovery status of any given node
// + White is undiscovered, Gray is in progress, Black is fully discovered
enum Color {White, Gray, Black};
// Information used in all searches
struct SearchInfo {
// Coloring of the nodes is used in both DFS and BFS
Color discovered = White;
};
/******************************************************************************/
// BFS search information struct
// BFS search information structs
// Node information that is only used in BFS
// Information that is only used in BFS
template <typename T>
struct BFS : NodeInfo {
struct BFS : SearchInfo {
// Used to represent distance from start node
int distance = 0;
// Used to represent the parent node that discovered this node
@@ -99,16 +49,12 @@ struct BFS : NodeInfo {
const Node<T> *predecessor = nullptr;
};
// Store search information in unordered_maps so we can pass it around easily
// + Allows each node to store relative information on the traversal
template <typename T> using InfoBFS = std::unordered_map<T, struct BFS<T>>;
/******************************************************************************/
// DFS search information struct
// DFS search information structs
// Node information that is only used in DFS
struct DFS : NodeInfo {
// Information that is only used in DFS
struct DFS : SearchInfo {
// Create a pair to track discovery / finish time
// + Discovery time is the iteration the node is first discovered
// + Finish time is the iteration the node has been checked completely
@@ -116,16 +62,22 @@ struct DFS : NodeInfo {
std::pair<int, int> discoveryFinish;
};
template <typename T> using InfoDFS = std::unordered_map<T, struct DFS>;
/******************************************************************************/
// MST search information struct
// Alias types for storing search information structures
// Store search information in unordered_maps so we can pass it around easily
// + Allows each node to store relative information on the traversal
template <typename T> using InfoBFS = std::unordered_map<T, struct BFS<T>>;
template <typename T> using InfoDFS = std::unordered_map<T, struct DFS>;
// Edges stored as multimap<weight, pair<nodeA.data_, nodeB.data_>>
template <typename T> using Edges = std::multimap<int, std::pair<T, T>>;
struct MST : NodeInfo {
/******************************************************************************/
// MST search information structs
struct MST : SearchInfo {
int32_t parent = INT32_MIN;
int rank = 0;
};
@@ -134,9 +86,8 @@ template <typename T>
struct InfoMST {
template <typename> friend class Graph;
explicit InfoMST(const std::vector<Node<T>> &nodes)
{
for (const auto &node : nodes) {
explicit InfoMST(const std::vector<Node<T>> &nodes) {
for (const auto &node : nodes){
// Initialize the default values for forest tracked by this struct
// + This data is used in KruskalMST() to find the MST
MakeSet(node.data_);
@@ -206,6 +157,51 @@ private:
};
/******************************************************************************/
// Node structure for representing a graph
template <typename T>
struct Node {
public:
template <typename> friend class Graph;
template <typename> friend class InfoMST;
// Constructors
Node(const Node &rhs) = default;
Node & operator=(Node rhs) {
if (this == &rhs) return *this;
swap(*this, rhs);
return *this;
}
Node(T data, const std::vector<std::pair<T, int>> &adj)
: data_(data)
{
// Place each adjacent node in vector into our unordered_map of edges
for (const auto &i : adj) adjacent_.emplace(i.first, i.second);
}
friend void swap(Node &a, Node &b) {
std::swap(a.data_, b.data_);
std::swap(a.adjacent_, b.adjacent_);
}
// Operators
// Define operator== for std::find; And comparisons between nodes
bool operator==(const Node<T> &b) const { return this->data_ == b.data_;}
// Define an operator!= for comparing nodes for inequality
bool operator!=(const Node<T> &b) const { return this->data_ != b.data_;}
// Accessors
inline T GetData() const { return data_;}
inline std::unordered_map<int, int> GetAdjacent() const { return adjacent_;}
private:
T data_;
// Adjacent stored in an unordered_map<adj.number, edgeWeight>
std::unordered_map<T, int> adjacent_;
};
/******************************************************************************/
// Templated graph class
@@ -213,7 +209,7 @@ template <class T>
class Graph {
public:
// Constructor
explicit Graph(std::vector<Node<T>> nodes) : nodes_(std::move(nodes)) {}
Graph(std::vector<Node<T>> nodes) : nodes_(std::move(nodes)) {}
// Breadth First Search
InfoBFS<T> BFS(const Node<T>& startNode) const;

View File

@@ -1,7 +1,8 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Driver program to test weighted graph implementation ##
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: An example of a weighted graph implementation ##
## Algorithms in this example are found in MIT Intro to Algorithms ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
@@ -104,7 +105,7 @@ int main (const int argc, const char * argv[])
// + Chapter 22, Figure 22.4 on DFS
// Unlike the simple-graph example, this final result matches MIT Algorithms
// + Aside from the placement of the watch node, which is not connected
// + This is because the node is visited after all other nodes are finished
// + This is because the node is visited after all other nodes are finished
std::vector<Node> order =
topologicalGraph.TopologicalSort(topologicalGraph.GetNodeCopy(6));
std::cout << "\nTopological order: ";
@@ -156,19 +157,11 @@ int main (const int argc, const char * argv[])
{9, {{3, 2}, {7, 6}}}
}
);
std::cout << "\nChecking weight traversing graph from node 1 using DFS...\n";
InfoDFS resultDFS = graphMST.DFS(graphMST.GetNodeCopy(1));
std::cout << "DFS total weight traversed: " << resultDFS.totalWeight << std::endl;
std::cout << "\nChecking weight traversing graph from node 1 using BFS...\n";
InfoBFS resultBFS = graphMST.BFS(graphMST.GetNodeCopy(1));
std::cout << "BFS total weight traversed: " << resultBFS.totalWeight << std::endl;
InfoMST resultMST = graphMST.KruskalMST();
std::cout << "\n\nFinding MST using Kruskal's...\n\nMST result: \n";
std::cout << "Finding MST using Kruskal's...\n\nMST result: \n";
for (const auto &edge : resultMST.edgesMST) {
std::cout << "Connected nodes: " << edge.second.first << "->"
<< edge.second.second << " with weight of " << edge.first << "\n";
}
std::cout << "Total MST weight: " << resultMST.totalWeight << std::endl;
std::cout << "Total MST weight: " << resultMST.weightMST << std::endl;
}

View File

@@ -1,8 +1,7 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: An example of a weighted graph implementation ##
## Algorithms in this example are found in MIT Intro to Algorithms ##
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: Driver program to test object graph implementation ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
@@ -14,13 +13,13 @@
InfoBFS Graph::BFS(const Node& startNode) const
{
// Create local object to track the information gathered during traversal
InfoBFS bfs;
InfoBFS searchInfo;
// Create a queue to visit discovered nodes in FIFO order
std::queue<const Node *> visitQueue;
// Mark the startNode as in progress until we finish checking adjacent nodes
bfs.nodeInfo[startNode.number].discovered = Gray;
searchInfo[startNode.number].discovered = Gray;
// Visit the startNode
visitQueue.push(&startNode);
@@ -31,17 +30,17 @@ InfoBFS Graph::BFS(const Node& startNode) const
const Node * thisNode = visitQueue.front();
visitQueue.pop();
std::cout << "Visiting node " << thisNode->number << std::endl;
// Check if we have already discovered all the adjacentNodes to thisNode
for (const auto &adjacent : thisNode->adjacent) {
if (bfs.nodeInfo[adjacent.first].discovered == White) {
if (searchInfo[adjacent.first].discovered == White) {
std::cout << "Found undiscovered adjacentNode: " << adjacent.first
<< " with weight of " << adjacent.second << std::endl;
bfs.totalWeight += adjacent.second;
<< "\n";
// Mark the adjacent node as in progress
bfs.nodeInfo[adjacent.first].discovered = Gray;
bfs.nodeInfo[adjacent.first].distance =
bfs.nodeInfo[thisNode->number].distance + 1;
bfs.nodeInfo[adjacent.first].predecessor =
searchInfo[adjacent.first].discovered = Gray;
searchInfo[adjacent.first].distance =
searchInfo[thisNode->number].distance + 1;
searchInfo[adjacent.first].predecessor =
&GetNode(thisNode->number);
// Add the discovered node the the visitQueue
@@ -49,11 +48,11 @@ InfoBFS Graph::BFS(const Node& startNode) const
}
}
// We are finished with this node and the adjacent nodes; Mark it discovered
bfs.nodeInfo[thisNode->number].discovered = Black;
searchInfo[thisNode->number].discovered = Black;
}
// Return the information gathered from this search, JIC caller needs it
return bfs;
return searchInfo;
}
std::deque<Node> Graph::PathBFS(const Node &start, const Node &finish) const
@@ -62,8 +61,8 @@ std::deque<Node> Graph::PathBFS(const Node &start, const Node &finish) const
// + If the caller modifies these, it will not impact the graph's data
std::deque<Node> path;
InfoBFS bfs = BFS(start);
const Node * next = bfs.nodeInfo[finish.number].predecessor;
InfoBFS searchInfo = BFS(start);
const Node * next = searchInfo[finish.number].predecessor;
bool isValid = false;
do {
// If we have reached the start node, we have found a valid path
@@ -74,7 +73,7 @@ std::deque<Node> Graph::PathBFS(const Node &start, const Node &finish) const
path.emplace_front(*next);
// Move to the next node
next = bfs.nodeInfo[next->number].predecessor;
next = searchInfo[next->number].predecessor;
} while (next != nullptr);
// Use emplace_back to call Node copy constructor
path.emplace_back(finish);
@@ -89,83 +88,85 @@ std::deque<Node> Graph::PathBFS(const Node &start, const Node &finish) const
InfoDFS Graph::DFS() const
{
// Track the nodes we have discovered
InfoDFS dfs;
InfoDFS searchInfo;
int time = 0;
// Visit each node in the graph
for (const auto & node : nodes_) {
for (const auto& node : nodes_) {
std::cout << "Visiting node " << node.number << std::endl;
// If the node is undiscovered, visit it
if (dfs.nodeInfo[node.number].discovered == White) {
if (searchInfo[node.number].discovered == White) {
std::cout << "Found undiscovered node: " << node.number << std::endl;
// Visiting the undiscovered node will check it's adjacent nodes
DFSVisit(time, node, dfs);
DFSVisit(time, node, searchInfo);
}
}
return dfs;
return searchInfo;
}
InfoDFS Graph::DFS(const Node &startNode) const
{
// Track the nodes we have discovered
InfoDFS dfs;
InfoDFS searchInfo;
int time = 0;
auto startIter =
std::find(nodes_.begin(), nodes_.end(), Node(startNode.number, { }));
auto startIter = std::find(nodes_.begin(), nodes_.end(),
Node(startNode.number, {})
);
// beginning at startNode, visit each node in the graph until we reach the end
while (startIter != nodes_.end()) {
std::cout << "Visiting node " << startIter->number << std::endl;
// If the startIter is undiscovered, visit it
if (dfs.nodeInfo[startIter->number].discovered == White) {
std::cout << "Found undiscovered node: " << startIter->number
<< std::endl;
if (searchInfo[startIter->number].discovered == White) {
std::cout << "Found undiscovered node: " << startIter->number << std::endl;
// Visiting the undiscovered node will check it's adjacent nodes
DFSVisit(time, *startIter, dfs);
DFSVisit(time, *startIter, searchInfo);
}
startIter++;
}
// Once we reach the last node, check the beginning for unchecked nodes
startIter = nodes_.begin();
// Once we reach the initial startNode, we have checked all nodes
while (*startIter != startNode) {
std::cout << "Visiting node " << startIter->number << std::endl;
// If the startIter is undiscovered, visit it
if (dfs.nodeInfo[startIter->number].discovered == White) {
if (searchInfo[startIter->number].discovered == White) {
std::cout << "Found undiscovered node: " << startIter->number << std::endl;
// Visiting the undiscovered node will check it's adjacent nodes
DFSVisit(time, *startIter, dfs);
DFSVisit(time, *startIter, searchInfo);
}
startIter++;
}
return dfs;
return searchInfo;
}
void Graph::DFSVisit(int &time, const Node& startNode, InfoDFS &dfs) const
void Graph::DFSVisit(int &time, const Node& startNode, InfoDFS &searchInfo) const
{
dfs.nodeInfo[startNode.number].discovered = Gray;
searchInfo[startNode.number].discovered = Gray;
time++;
dfs.nodeInfo[startNode.number].discoveryFinish.first = time;
searchInfo[startNode.number].discoveryFinish.first = time;
// Check the adjacent nodes of the startNode
for (const auto & adjacent : startNode.adjacent) {
const auto node = GetNode(adjacent.first);
for (const auto &adjacent : startNode.adjacent) {
auto iter = std::find(nodes_.begin(), nodes_.end(),
Node(adjacent.first, {}));
// If the adjacentNode is undiscovered, visit it
// + Offset by 1 to account for 0 index of discovered vector
if (dfs.nodeInfo[node.number].discovered == White) {
std::cout << "Found undiscovered adjacentNode: " << adjacent.first
<< " with weight of " << adjacent.second << std::endl;
if (searchInfo[iter->number].discovered == White) {
std::cout << "Found undiscovered adjacentNode: "
<< GetNode(adjacent.first).number << std::endl;
// Visiting the undiscovered node will check it's adjacent nodes
dfs.totalWeight += adjacent.second;
DFSVisit(time, node, dfs);
DFSVisit(time, *iter, searchInfo);
}
}
dfs.nodeInfo[startNode.number].discovered = Black;
searchInfo[startNode.number].discovered = Black;
time++;
dfs.nodeInfo[startNode.number].discoveryFinish.second = time;
searchInfo[startNode.number].discoveryFinish.second = time;
}
std::vector<Node> Graph::TopologicalSort(const Node &startNode) const
@@ -175,8 +176,8 @@ std::vector<Node> Graph::TopologicalSort(const Node &startNode) const
std::vector<Node> order(nodes_);
auto comp = [&topological](const Node &a, const Node &b) {
return (topological.nodeInfo[a.number].discoveryFinish.second <
topological.nodeInfo[b.number].discoveryFinish.second);
return (topological[a.number].discoveryFinish.second <
topological[b.number].discoveryFinish.second);
};
std::sort(order.begin(), order.end(), comp);
@@ -188,26 +189,27 @@ std::vector<Node> Graph::TopologicalSort(const Node &startNode) const
InfoMST Graph::KruskalMST() const
{
InfoMST mst(nodes_);
InfoMST searchInfo(nodes_);
// The ctor for InfoMST initializes all edges within the graph into a multimap
// + Key for multimap is edge weight, so they're already sorted in ascending
// For each edge in the graph, check if they are part of the same tree
// + Since we do not want to create a cycle in the MST forest -
// + we don't connect nodes that are part of the same tree
for (const auto &edge : mst.edges) {
for (const auto &edge : searchInfo.edges) {
// Two integers representing the node.number for the connected nodes
const int u = edge.second.first;
const int v = edge.second.second;
// Check if the nodes are of the same tree
if (mst.FindSet(u) != mst.FindSet(v)) {
if (searchInfo.FindSet(u) != searchInfo.FindSet(v)) {
// If they are not, add the edge to our MST
mst.edgesMST.emplace(edge);
mst.totalWeight += edge.first;
searchInfo.edgesMST.emplace(edge);
searchInfo.weightMST += edge.first;
// Update the forest to reflect this change
mst.Union(u, v);
searchInfo.Union(u, v);
}
}
return mst;
return searchInfo;
}

View File

@@ -1,7 +1,7 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: An example of a weighted graph implementation ##
## Legal: All Content (c) 2021 Shaun Reed, all rights reserved ##
## About: An example of an object graph implementation ##
## Algorithms in this example are found in MIT Intro to Algorithms ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
@@ -10,14 +10,56 @@
#ifndef LIB_GRAPH_HPP
#define LIB_GRAPH_HPP
#include <algorithm>
#include <iostream>
#include <algorithm>
#include <map>
#include <queue>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
#include <queue>
#include <unordered_set>
#include <unordered_map>
/******************************************************************************/
// Structures for tracking information gathered from various traversals
struct Node;
// Color represents the discovery status of any given node
// + White is undiscovered, Gray is in progress, Black is fully discovered
enum Color {White, Gray, Black};
// Information used in all searches
struct SearchInfo {
// Coloring of the nodes is used in both DFS and BFS
Color discovered = White;
};
// Information that is only used in BFS
struct BFS : SearchInfo {
// Used to represent distance from start node
int distance = 0;
// Used to represent the parent node that discovered this node
// + If we use this node as the starting point, this will remain a nullptr
const Node *predecessor = nullptr;
};
// Information that is only used in DFS
struct DFS : SearchInfo {
// Create a pair to track discovery / finish time
// + Discovery time is the iteration the node is first discovered
// + Finish time is the iteration the node has been checked completely
// ++ A finished node has considered all adjacent nodes
std::pair<int, int> discoveryFinish;
};
struct MST : SearchInfo {
int32_t parent = INT32_MIN;
int rank = 0;
};
// Store search information in unordered_maps so we can pass it around easily
// + Allows each node to store relative information on the traversal
using InfoBFS = std::unordered_map<int, struct BFS>;
using InfoDFS = std::unordered_map<int, struct DFS>;
/******************************************************************************/
@@ -27,8 +69,7 @@ struct Node {
public:
// Constructors
Node(const Node &rhs) = default;
Node & operator=(Node rhs)
{
Node & operator=(Node rhs) {
if (this == &rhs) return *this;
swap(*this, rhs);
return *this;
@@ -39,8 +80,7 @@ public:
for (const auto &i : adj) adjacent.emplace(i.first, i.second);
}
friend void swap(Node &a, Node &b)
{
friend void swap(Node &a, Node &b) {
std::swap(a.number, b.number);
std::swap(a.adjacent, b.adjacent);
}
@@ -55,81 +95,10 @@ public:
bool operator!=(const Node &b) const { return this->number != b.number;}
};
/******************************************************************************/
// Base struct for storing traversal information on all nodes
// Color represents the discovery status of any given node
enum Color {
// Node is marked as undiscovered
White,
// Node discovery is in progress; Some adjacent nodes have not been checked
Gray,
// Node has been discovered; All adjacent nodes have been checked
Black
};
// Information used in all searches tracked for each node
struct NodeInfo {
// Coloring of the nodes is used in both DFS and BFS
Color discovered = White;
};
// Template for tracking graph information gathered during traversals
// + Used for DFS, BFS, and MST
template <typename T>
struct GraphInfo {
// Store search information in unordered_maps so we can pass it around easily
// + Allows each node to store relative information on the traversal
std::unordered_map<int, T> nodeInfo;
// Track total weight for all traversals
int totalWeight = 0;
};
/******************************************************************************/
// BFS search information struct
// Node search information that is only used in BFS
struct BFS : NodeInfo {
// Used to represent distance from start node
int distance = 0;
// Used to represent the parent node that discovered this node
// + If we use this node as the starting point, this will remain a nullptr
const Node *predecessor = nullptr;
};
struct InfoBFS : GraphInfo<BFS> {/* Members inherited from GraphInfo */};
/******************************************************************************/
// DFS search information struct
// Information that is only used in DFS
struct DFS : NodeInfo {
// Create a pair to track discovery / finish time
// + Discovery time is the iteration the node is first discovered
// + Finish time is the iteration the node has been checked completely
// ++ A finished node has considered all adjacent nodes
std::pair<int, int> discoveryFinish;
};
struct InfoDFS : GraphInfo<DFS> {/* Members inherited from GraphInfo */};
/******************************************************************************/
// MST search information struct
struct MST : NodeInfo {
int32_t parent = INT32_MIN;
int rank = 0;
};
using Edges = std::multimap<int, std::pair<int, int>>;
struct InfoMST : GraphInfo<MST>{
explicit InfoMST(const std::vector<Node> &nodes)
{
for (const auto &node : nodes) {
struct InfoMST {
explicit InfoMST(const std::vector<Node> &nodes) {
for (const auto &node : nodes){
// Initialize the default values for forest tracked by this struct
// + This data is used in KruskalMST() to find the MST
MakeSet(node.number);
@@ -144,17 +113,20 @@ struct InfoMST : GraphInfo<MST>{
}
}
std::unordered_map<int, struct MST> searchInfo;
// All of the edges within our graph
// + Since each node stores its own edges, this is initialized in InfoMST ctor
Edges edges;
// A multimap of the edges found for our MST
Edges edgesMST;
// The total weight of our resulting MST
int weightMST = 0;
void MakeSet(int x)
{
nodeInfo[x].parent = x;
nodeInfo[x].rank = 0;
searchInfo[x].parent = x;
searchInfo[x].rank = 0;
}
void Union(int x, int y)
@@ -164,30 +136,29 @@ struct InfoMST : GraphInfo<MST>{
void Link(int x, int y)
{
if (nodeInfo[x].rank > nodeInfo[y].rank) {
nodeInfo[y].parent = x;
if (searchInfo[x].rank > searchInfo[y].rank) {
searchInfo[y].parent = x;
}
else {
nodeInfo[x].parent = y;
if (nodeInfo[x].rank == nodeInfo[y].rank) {
nodeInfo[y].rank += 1;
searchInfo[x].parent = y;
if (searchInfo[x].rank == searchInfo[y].rank) {
searchInfo[y].rank += 1;
}
}
}
int FindSet(int x)
{
if (x != nodeInfo[x].parent) {
nodeInfo[x].parent = FindSet(nodeInfo[x].parent);
if (x != searchInfo[x].parent) {
searchInfo[x].parent = FindSet(searchInfo[x].parent);
}
return nodeInfo[x].parent;
return searchInfo[x].parent;
}
};
};
/******************************************************************************/
// Graph class declaration
class Graph {
public:
// Constructor
@@ -202,7 +173,7 @@ public:
// An alternate DFS that checks each node of the graph beginning at startNode
InfoDFS DFS(const Node &startNode) const;
// Visit function is used in both versions of DFS
void DFSVisit(int &time, const Node& startNode, InfoDFS &dfs) const;
void DFSVisit(int &time, const Node& startNode, InfoDFS &searchInfo) const;
// Topological sort, using DFS
std::vector<Node> TopologicalSort(const Node &startNode) const;
// Kruskal's MST

View File

@@ -1,31 +0,0 @@
################################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Practice project for testing with catch2 framework ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
cmake_minimum_required(VERSION 3.15)
project(
#[[NAME]] Catch2
VERSION 1.0
DESCRIPTION "Practice project for learning Catch2"
LANGUAGES CXX
)
add_compile_options(-Wall)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/bin)
Include(FetchContent)
FetchContent_Declare(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v3.0.1
)
FetchContent_MakeAvailable(Catch2)
add_subdirectory(src)
add_subdirectory(test)

View File

@@ -1,10 +0,0 @@
#ifndef KLIPS_KLIPS_H
#define KLIPS_KLIPS_H
class klips { };
unsigned int factorial(unsigned int);
#endif // KLIPS_KLIPS_H

View File

@@ -1,29 +0,0 @@
// Authored by 康桓瑋 on SO: https://stackoverflow.com/a/56766138
#ifndef CATCH2_TYPE_NAME_HPP
#include <string_view>
template <typename T>
constexpr auto type_name() {
std::string_view name, prefix, suffix;
#ifdef __clang__
name = __PRETTY_FUNCTION__;
prefix = "auto type_name() [T = ";
suffix = "]";
#elif defined(__GNUC__)
name = __PRETTY_FUNCTION__;
prefix = "constexpr auto type_name() [with T = ";
suffix = "]";
#elif defined(_MSC_VER)
name = __FUNCSIG__;
prefix = "auto __cdecl type_name<";
suffix = ">(void)";
#endif
name.remove_prefix(prefix.size());
name.remove_suffix(suffix.size());
return name;
}
#define CATCH2_TYPE_NAME_HPP
#endif // CATCH2_TYPE_NAME_HPP

View File

@@ -1,22 +0,0 @@
################################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Practice project for testing with catch2 framework ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
cmake_minimum_required(VERSION 3.15)
project(
#[[NAME]] Catch2
VERSION 1.0
DESCRIPTION "Practice project for learning Catch2"
LANGUAGES CXX
)
add_compile_options(-Wall)
add_definitions("-std=c++17")
add_library(klips SHARED klips.cpp)
target_include_directories(klips PRIVATE ${CMAKE_SOURCE_DIR}/include)

View File

@@ -1,4 +0,0 @@
unsigned int factorial( unsigned int number ) {
return number <= 1 ? number : factorial(number-1)*number;
}

View File

@@ -1,22 +0,0 @@
################################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Practice project for testing with catch2 framework ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
cmake_minimum_required(VERSION 3.15)
project(
#[[NAME]] Catch2
VERSION 1.0
DESCRIPTION "Practice project for learning Catch2"
LANGUAGES CXX
)
add_compile_options(-Wall)
add_executable(test_klips test_klips.cpp)
target_link_libraries(test_klips PRIVATE Catch2::Catch2WithMain klips)
target_include_directories(test_klips PRIVATE ${CMAKE_SOURCE_DIR}/include)

View File

@@ -1,147 +0,0 @@
#define CATCH_CONFIG_MAIN
#include <iostream>
#include "../bin/catch.hpp"
#include "klips.hpp"
#include "type_name.hpp"
#define TT() std::cout << "T = " << type_name<TestType>() << std::endl;
#define TD(x) \
std::cout << type_name<decltype(x)>() << " " << #x << " = " << x << std::endl;
#define T(x) std::cout << "T = " << type_name<x>() << std::endl;
TEST_CASE("factorials are computed", "[factorial]") {
REQUIRE(factorial(1) == 1);
REQUIRE(factorial(2) == 2);
REQUIRE(factorial(3) == 6);
REQUIRE(factorial(10) == 3628800);
}
TEST_CASE("Generators") {
auto i = GENERATE(1, 3, 5);
TD(i);
}
TEST_CASE("Generators 2") {
auto i = GENERATE(1, 2);
SECTION("one") {
auto j = GENERATE(-3, -2);
REQUIRE(j < i);
std::cout << "i = " << i << "; j = " << j << std::endl;
}
SECTION("two") {
auto k = GENERATE(4, 5, 6);
REQUIRE(i != k);
std::cout << "i = " << i << "; k = " << k << std::endl;
}
}
TEST_CASE("Complex mix of sections and generates") {
auto i = GENERATE(1, 2);
SECTION("A") {
std::cout << "i = " << i << "; A passed" << std::endl;
SUCCEED("A");
}
std::cout << "left A\n";
auto j = GENERATE(3, 4);
std::cout << "i = " << i << "; j = " << j << std::endl;
SECTION("B") {
std::cout << "i = " << i << "; j = " << j << "; B passed;" << std::endl;
SUCCEED("B");
}
auto k = GENERATE(5, 6);
std::cout << "i = " << i << "; k = " << k << std::endl;
SUCCEED();
}
TEST_CASE("Test generaators 3", "[test]") { GENERATE(values({1, 2})); }
TEMPLATE_TEST_CASE("Testing template tests", "[test][template]", int8_t,
int16_t, int32_t, int64_t) {
TT();
}
template <typename T> struct Foo {
size_t size() { return 0; }
};
template <typename T> struct Test {
T test() {
T x;
return x;
}
};
TEMPLATE_PRODUCT_TEST_CASE("A Template product test case",
"[template][product]", (std::vector, Test),
(int, float)) {
TT();
}
TEMPLATE_PRODUCT_TEST_CASE("Product with differing arities",
"[template][product]", std::tuple,
(int, (int, double), (int, double, float))) {
TT();
}
using types = std::tuple<int8_t, int16_t, int32_t, int64_t>;
TEMPLATE_LIST_TEST_CASE("Testing template list tests", "[test][template][list]",
types) {
TT();
}
TEMPLATE_TEST_CASE_SIG(
"TemplateTestSig: arrays can be created from NTTP arguments",
"[vector][template][nttp]", ((typename T, int V), T, V), (int, 5),
(float, 4), (std::string, 15), ((std::tuple<int, float>), 6)) {
T(T);
std::cout << "V = " << V;
std::array<T, V> v;
REQUIRE(v.size() > 1);
}
template <typename T, size_t S> struct Bar {
size_t size() { return S; }
};
TEMPLATE_PRODUCT_TEST_CASE_SIG(
"A Template product test case with array signature",
"[template][product][nttp]", ((typename T, size_t S), T, S),
(std::array, Bar), ((int, 9), (float, 42))) {
TT();
TestType x;
REQUIRE(x.size() > 0);
}
template <typename T> struct test_config_get {
template <bool must_find> void run() {
// Config c{};
// std::string key{"the_key"};
// std::string value{"the_value"};
// c.set(key, value);
if constexpr (must_find) {
std::cout << "Test 1 ran";
} else {
std::cout << "Test 2 ran";
}
}
};
template <> template <bool must_find> void test_config_get<std::string>::run() {
if constexpr (must_find) {
std::cout << "Test 1 ran for strings";
} else {
std::cout << "Test 2 ran for strings";
}
}
TEMPLATE_PRODUCT_TEST_CASE("Test", "[test]", test_config_get,
(int, std::string)) {
TT();
TestType t;
test_config_get<int> s;
s.template run<true>();
// TestType t;
// t.run<true>();
}

View File

@@ -15,10 +15,5 @@ project(
LANGUAGES CXX
)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
add_compile_options("-Wall")
add_subdirectory(conditions)
add_subdirectory(deadlock)
add_subdirectory(livelock)
add_subdirectory(race-condition)

View File

@@ -1,25 +0,0 @@
# Multithreading
A few basic multithreading programs written in C++ while learning about
the [concurrency support library](https://en.cppreference.com/w/cpp/thread)
```
klips/cpp/multithreading
.
├── conditions # Using condition_variable to control job execution flow
├── deadlock # Example of problem and solution for deadlocks
├── livelock # Example of problem and solution for livelocks
├── race-condition # Example of problem and solution for race conditions
└── README.md
```
We can build the examples with the following commands.
```bash
cd /path/to/klips/cpp/multithreading/
mkdir build && cd build
cmake .. && cmake --build .
ls bin/
multithread-conditions multithread-deadlock multithread-livelock multithread-race-condition
```

View File

@@ -1,26 +0,0 @@
################################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: An example of condition_variables in multithreaded C++ ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
cmake_minimum_required(VERSION 3.16)
# std::scoped_lock requires C++17
set(CMAKE_CXX_STANDARD 17)
add_compile_options("-Wall")
project(
#[[NAME]] ConditionVariables
VERSION 1.0
DESCRIPTION "Example of condition_variables in multithreaded C++"
LANGUAGES CXX
)
add_executable(
multithread-conditions driver.cpp
)
target_link_libraries(multithread-conditions pthread)

View File

@@ -1,62 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: An example of condition_variables in multithreaded C++ ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
static std::mutex mtx;
std::condition_variable cv;
bool processing = false;
// Starts a job that waits for kick-off from main
// + When job finishes, handoff result back to main via processing bool
void job(int32_t & shared) {
std::unique_lock uniqueLock(mtx);
cv.wait(uniqueLock, []()->bool {return processing;});
std::cout << std::this_thread::get_id()
<< " thread_A: Initial value of shared = " << shared << std::endl;
while (shared < INT32_MAX) {
shared++;
}
// We're no longer processing data
processing = false;
std::cout << std::this_thread::get_id()
<< " thread_A: Done working." << std::endl;
uniqueLock.unlock(); // Important! Unlock uniqueLock before we notify
// Notify main that we've finished, so it can proceed
cv.notify_one();
}
int main(const int argc, const char * argv[]) {
std::cout << "main() thread id: " << std::this_thread::get_id() << std::endl;
int32_t share = 0;
std::thread thread_A(job, std::ref(share));
mtx.lock();
std::this_thread::sleep_for(std::chrono::seconds(3));
share = INT32_MAX / 2;
processing = true;
mtx.unlock();
// Notify thread_A that its work can begin
cv.notify_one();
// Wait until thread_A finishes its work
std::unique_lock uniqueLock(mtx);
// Block execution until we are not processing
cv.wait(uniqueLock, []()->bool { return !processing;});
std::cout << std::this_thread::get_id() << " main(): final value of shared = "
<< share << std::endl;
thread_A.join();
return 0;
}

View File

@@ -159,7 +159,7 @@ void solution_C() {
});
std::thread thread_B([]()->void {
std::scoped_lock scopedLock(mtx_B, mtx_A);
std::scoped_lock scopedLock(mtx_A, mtx_B);
print_safe(id_string(std::this_thread::get_id()) + ": Locked B, A");
std::this_thread::sleep_for(std::chrono::seconds(1));

View File

@@ -1,26 +0,0 @@
################################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: An example and solution for livelocks in C++ ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
cmake_minimum_required(VERSION 3.16)
# std::scoped_lock requires C++17
set(CMAKE_CXX_STANDARD 17)
add_compile_options("-Wall")
project(
#[[NAME]] LiveLock
VERSION 1.0
DESCRIPTION "Example and solution for livelocks in C++"
LANGUAGES CXX
)
add_executable(
multithread-livelock driver.cpp
)
target_link_libraries(multithread-livelock pthread)

View File

@@ -1,117 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: An example and solution for livelocks in C++ ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#include <chrono>
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
static std::mutex mtx_A, mtx_B, output;
// Helper function to output thread ID and string associated with mutex name
// + This must also be thread-safe, since we want threads to produce output
// + There is no bug or issue here; This is just in support of example output
void print_safe(const std::string & s) {
std::scoped_lock<std::mutex> scopedLock(output);
std::cout << s << std::endl;
}
void problem() {
// Construct a vector with 5 agreed-upon times to synchronize loops in threads
typedef std::chrono::time_point<std::chrono::steady_clock,
std::chrono::steady_clock::duration> time_point;
std::vector<time_point> waitTime(6);
for (uint8_t i = 0; i < 6; i++) {
waitTime[i] = std::chrono::steady_clock::now()+std::chrono::seconds(1+i);
}
std::thread thread_A([waitTime]()->void {
uint8_t count = 0; // Used to select time slot from waitTime vector
bool done = false;
while (!done) {
count++;
std::lock_guard l(mtx_A);
std::cout << std::this_thread::get_id() << " thread_A: Lock A\n";
// Wait until the next time slot to continue
// + Helps to show example of livelock by ensuring B is not available
std::this_thread::sleep_until(waitTime[count]);
std::cout << std::this_thread::get_id() << " thread_A: Requesting B\n";
if (mtx_B.try_lock()) {
done = true;
std::cout << std::this_thread::get_id()
<< " thread_A: Acquired locks for A, B! Done.\n";
}
else {
std::cout << std::this_thread::get_id()
<< " thread_A: Can't lock B, unlocking A\n";
}
}
mtx_B.unlock();
});
std::thread thread_B([waitTime]()->void {
// As an example, enter livelock for only 5 iterations
// + Also used to select time slot from waitTime vector
uint8_t count = 0;
bool done = false;
while (!done && count < 5) {
count++;
std::lock_guard l(mtx_B);
// Wait until the next time slot to continue
// + Helps to show example of livelock by ensuring A is not available
std::this_thread::sleep_until(waitTime[count]);
if (mtx_A.try_lock()) {
// The program will never reach this point in the code
// + The only reason livelock ends is because count > 5
done = true;
}
}
});
thread_A.join();
thread_B.join();
}
// The solution below uses std::scoped_lock to avoid the livelock problem
void solution() {
std::thread thread_A([]()->void {
for (int i = 0; i < 5; i++) {
// Increase wait time with i
// + To encourage alternating lock ownership between threads
std::this_thread::sleep_for(std::chrono::milliseconds(100 * i));
std::scoped_lock l(mtx_A, mtx_B);
std::cout << std::this_thread::get_id()
<< " thread_A: Acquired locks for A, B!" << std::endl;
}
});
std::thread thread_B([]()->void {
for (int i = 0; i < 5; i++) {
std::this_thread::sleep_for(std::chrono::milliseconds(100 * i));
std::scoped_lock l(mtx_B, mtx_A);
std::cout << std::this_thread::get_id()
<< " thread_B: Acquired locks for B, A!" << std::endl;
}
});
thread_A.join();
thread_B.join();
}
int main(const int argc, const char * argv[]) {
std::cout << "main() thread id: " << std::this_thread::get_id() << std::endl;
problem();
std::cout << "\nSolution:\n\n";
solution();
return 0;
}

View File

@@ -1,24 +0,0 @@
################################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: A root project for practicing Qt 6 projects in C++ ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
cmake_minimum_required(VERSION 3.15)
project(
#[[NAME]] Klips
VERSION 1.0
DESCRIPTION "A root project for several small Qt6 practice projects"
LANGUAGES CXX
)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
add_compile_options("-Wall")
add_subdirectory(designer)
add_subdirectory(designer-plugin)
add_subdirectory(designer-plugin-collection)
add_subdirectory(slots)

View File

@@ -1,32 +0,0 @@
# Cpp
```bash
shaunrd0/klips/cpp/qt/
├── designer # Using Qt Designer to create application GUI
├── designer-plugin # Adding custom widgets as Qt Designer plugins
├── designer-plugin-collection # Adding a collection of widget plugins to Qt Designer
└── README.md
```
This directory contains a `CMakeLists.txt`, which can be selected to open as a
project within your preferred IDE. From there, all nested examples can be built,
debugged, and ran.
The plugin examples will need to be installed for Qt Designer integration to work.
On Linux, Qt Designer looks under `/some/path/to/Qt/Tools/QtCreator/lib/Qt/plugins/designer/`.
On windows or Mac, this path may differ. Unfortunately I don't have these machines to test for myself.
```bash
cd klips/cpp/qt/designer-plugin-collection
mkdir build && cd build
cmake .. && cmake --build . --target install
```
After installing the plugin collection example above, we can open Qt Creator and navigate to the Designer.
We should see the custom collection is available within the Designer, and the contents of the widgets render correctly in the application view.
![side-panel-view.png](side-panel-view.png)
![plugin-render-view.png](plugin-render-view.png)

View File

@@ -1,110 +0,0 @@
################################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Example of making a collection of widget plugins for Qt Designer ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
cmake_minimum_required(VERSION 3.15)
project(
#[[NAME]] DesignerPluginCollection
VERSION 1.0
DESCRIPTION "Example of a widget plugin collection for Qt Designer"
LANGUAGES CXX
)
include(GenerateExportHeader)
add_compile_options(-Wall)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_SHARED_MODULE_PREFIX "")
set(QT_DIR "$ENV{HOME}/Code/Clones/Qt/" CACHE PATH "Path to Qt6")
# Qt Designer will look in different locations if WIN / Unix.
# These paths are for using Qt Designer integrated within Qt Creator.
# Standalone Qt Designer may use different paths.
if (WIN32)
set(QT_PLUGIN_INSTALL_DIR
"${QT_DIR}/Tools/QtCreator/bin/plugins/designer"
)
# This path may be different on windows. I have not tested this.
set(QT_PLUGIN_LIBRARY_DIR
"${QT_DIR}/Tools/QtCreator/lib/Qt/lib"
)
else()
set(QT_PLUGIN_INSTALL_DIR
"${QT_DIR}/Tools/QtCreator/lib/Qt/plugins/designer"
)
set(QT_PLUGIN_LIBRARY_DIR
"${QT_DIR}/Tools/QtCreator/lib/Qt/lib"
)
endif()
# This should be set to your Qt6 installation directory.
set(QT_INSTALL_DIR "${QT_DIR}/6.3.1/gcc_64/" CACHE PATH "Path to Qt6 install")
list(APPEND CMAKE_PREFIX_PATH "${QT_INSTALL_DIR}")
find_package(Qt6 REQUIRED COMPONENTS UiPlugin Core Gui Widgets)
# Creating a library with two plugins for the collection.
qt_add_library(widget-plugin-library
textview.cpp textview.h
widgetplugin.cpp widgetplugin.h
)
target_sources(widget-plugin-library PRIVATE
textview.cpp textview.h
treeview.cpp treeview.h
widgetplugin.cpp widgetplugin.h
)
set_target_properties(widget-plugin-library PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(widget-plugin-library
PUBLIC Qt::UiPlugin Qt::Core Qt::Gui Qt::Widgets
)
install(TARGETS widget-plugin-library
RUNTIME DESTINATION "${QT_PLUGIN_LIBRARY_DIR}"
BUNDLE DESTINATION "${QT_PLUGIN_LIBRARY_DIR}"
LIBRARY DESTINATION "${QT_PLUGIN_LIBRARY_DIR}"
)
generate_export_header(widget-plugin-library)
# Creating the collection
qt_add_library(widget-plugin-collection
widgetplugincollection.cpp widgetplugincollection.h
)
target_link_libraries(widget-plugin-collection
Qt6::Widgets Qt6::UiPlugin widget-plugin-library
)
install(TARGETS widget-plugin-collection
RUNTIME DESTINATION "${QT_PLUGIN_INSTALL_DIR}"
BUNDLE DESTINATION "${QT_PLUGIN_INSTALL_DIR}"
LIBRARY DESTINATION "${QT_PLUGIN_INSTALL_DIR}"
)
# Application that will use the widget plugin
set(APP_DIR ${CMAKE_CURRENT_SOURCE_DIR})
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/app-dir.h.in"
"${CMAKE_CURRENT_SOURCE_DIR}/app-dir.h"
@ONLY
)
qt_add_executable(widget-app
widgetapp.cpp widgetapp.h widgetapp.ui
main.cpp
)
target_link_libraries(widget-app
PRIVATE Qt::Widgets widget-plugin-library
)

View File

@@ -1,6 +0,0 @@
#ifndef APPDIR_H_IN
#define APPDIR_H_IN
#define APP_DIR "/home/kapper/Code/klips/cpp/qt/designer-plugin-collection"
#endif // APPDIR_H_IN

View File

@@ -1,6 +0,0 @@
#ifndef APPDIR_H_IN
#define APPDIR_H_IN
#define APP_DIR "@APP_DIR@"
#endif // APPDIR_H_IN

View File

@@ -1,18 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Main driver fprogram for practice using signals and slots in Qt ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#include "widgetapp.h"
#include <QApplication>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
WidgetApp widgetApp;
widgetApp.show();
return app.exec();
}

View File

@@ -1,10 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Text viewer for signals and slots examples ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#include "textview.h"

View File

@@ -1,44 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Text viewer for signals and slots examples ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#ifndef KLIPS_TEXTVIEW_H
#define KLIPS_TEXTVIEW_H
#include "widget-plugin-library_export.h"
#include <QPlainTextEdit>
class WIDGET_PLUGIN_LIBRARY_EXPORT TextView : public QPlainTextEdit {
Q_OBJECT
public:
explicit TextView(QWidget *parent = nullptr) : QPlainTextEdit(parent) {
appendPlainText("This is an example of a custom QTextView widget.");
}
~TextView() = default;
QString includeFile() const { return QStringLiteral("text-view.h"); };
public:
signals:
void sendTest();
private:
signals:
void sentTestPrivate();
public slots:
void test() { appendPlainText("Test signal received by TextView."); }
void testArgs(const QString &message) { appendPlainText(message); }
private slots:
void testPrivate() {}
};
#endif // KLIPS_TEXTVIEW_H

View File

@@ -1,10 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Tree viewer ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#include "treeview.h"

View File

@@ -1,36 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Tree viewer ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#ifndef KLIPS_TREEVIEW_H
#define KLIPS_TREEVIEW_H
#include "widget-plugin-library_export.h"
#include <app-dir.h>
#include <QFileSystemModel>
#include <QSortFilterProxyModel>
#include <QTreeView>
class WIDGET_PLUGIN_LIBRARY_EXPORT TreeView : public QTreeView {
Q_OBJECT
public:
explicit TreeView(QWidget *parent = nullptr) : QTreeView(parent) {
QFileSystemModel *model = new QFileSystemModel;
QSortFilterProxyModel *proxy = new QSortFilterProxyModel(this);
QModelIndex rootModelIndex = model->setRootPath(APP_DIR);
proxy->setSourceModel(model);
setModel(proxy);
setRootIndex(proxy->mapFromSource(rootModelIndex));
}
~TreeView() = default;
};
#endif // KLIPS_TREEVIEW_H

View File

@@ -1,15 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Application that uses widget from the collection ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#include "widgetapp.h"
WidgetApp::WidgetApp(QWidget *parent) : QMainWindow(parent) {
m_widgetApp = new Ui::MainWindow;
m_widgetApp->setupUi(this);
}

View File

@@ -1,37 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Application that uses a custom Qt Designer widget plugin ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#ifndef KLIPS_WIDGETAPP_H
#define KLIPS_WIDGETAPP_H
#include <QDockWidget>
#include <QMainWindow>
#include <QPlainTextEdit>
#include <QVBoxLayout>
#include <QWidget>
#include "ui_widgetapp.h"
class WidgetApp : public QMainWindow {
Q_OBJECT
public:
explicit WidgetApp(QWidget *parent = nullptr);
~WidgetApp() = default;
Ui::MainWindow * m_widgetApp;
public:
signals:
void sendTest();
public slots:
void test(){};
};
#endif // KLIPS_WIDGETAPP_H

View File

@@ -1,107 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<property name="enabled">
<bool>true</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_9">
<item>
<widget class="TextView" name="text-view_4" native="true"/>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="actionOption1"/>
<addaction name="actionOption2"/>
<addaction name="separator"/>
<addaction name="actionCategory_2"/>
</widget>
<widget class="QMenu" name="menuEdit">
<property name="title">
<string>Edit</string>
</property>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
<string>Help</string>
</property>
</widget>
<addaction name="menuFile"/>
<addaction name="menuEdit"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<widget class="QDockWidget" name="dockWidget_5">
<attribute name="dockWidgetArea">
<number>1</number>
</attribute>
<widget class="QWidget" name="dockWidgetContents_8">
<layout class="QHBoxLayout" name="horizontalLayout_10">
<item>
<widget class="TreeView" name="tree-view"/>
</item>
</layout>
</widget>
</widget>
<action name="actionOption1">
<property name="text">
<string>Option1</string>
</property>
</action>
<action name="actionOption2">
<property name="text">
<string>Option2</string>
</property>
</action>
<action name="actionCategory_2">
<property name="text">
<string>Section 2</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>TreeView</class>
<extends>QWidget</extends>
<header>treeview.h</header>
</customwidget>
<customwidget>
<class>TextView</class>
<extends>QWidget</extends>
<header>textview.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@@ -1,52 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Example of a generic Qt Designer widget plugin ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#include "widgetplugin.h"
#include "textview.h"
#include <QtPlugin>
#include <utility>
WidgetPlugin::WidgetPlugin(QString group, QString name,
WidgetPlugin::Factory factory)
: m_group(std::move(group)), m_name(std::move(name)),
m_includeFile(name + ".h"), m_factory(std::move(factory)) {}
WidgetPlugin::WidgetPlugin(QString group, QString name, QString include,
WidgetPlugin::Factory factory)
: m_group(std::move(group)), m_name(std::move(name)),
m_includeFile(std::move(include)), m_factory(std::move(factory)) {}
QString WidgetPlugin::toolTip() const { return {}; }
QString WidgetPlugin::whatsThis() const { return {}; }
QIcon WidgetPlugin::icon() const { return {}; }
bool WidgetPlugin::isContainer() const { return false; }
QString WidgetPlugin::group() const { return m_group; }
QString WidgetPlugin::name() const { return m_name; }
// TODO: The generated UI headers do not use this member appropriately.
QString WidgetPlugin::includeFile() const { return m_includeFile; }
QWidget *WidgetPlugin::createWidget(QWidget *parent) {
return m_factory(parent);
}
bool WidgetPlugin::isInitialized() const { return m_initialized; }
void WidgetPlugin::initialize(QDesignerFormEditorInterface *) {
if (m_initialized)
return;
m_initialized = true;
}

View File

@@ -1,52 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Example Qt Designer widget plugin ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#ifndef KLIPS_WIDGETPLUGIN_H
#define KLIPS_WIDGETPLUGIN_H
#include <QDesignerCustomWidgetInterface>
class WidgetPlugin : public QObject, public QDesignerCustomWidgetInterface {
Q_OBJECT
Q_PLUGIN_METADATA(IID "com.Klips.WidgetPlugin")
Q_INTERFACES(QDesignerCustomWidgetInterface)
using Factory = std::function<QWidget *(QWidget *)>;
public:
WidgetPlugin(QString group, QString name, Factory factory);
WidgetPlugin(QString group, QString name, QString include, Factory factory);
explicit WidgetPlugin(QObject *parent = nullptr) : QObject(parent) {}
~WidgetPlugin() = default;
public:
[[nodiscard]] QString group() const override;
[[nodiscard]] QString name() const override;
[[nodiscard]] QString includeFile() const override;
QWidget *createWidget(QWidget *parent) override;
[[nodiscard]] QString toolTip() const override;
[[nodiscard]] QString whatsThis() const override;
[[nodiscard]] QIcon icon() const override;
[[nodiscard]] bool isContainer() const override;
[[nodiscard]] bool isInitialized() const override;
void initialize(QDesignerFormEditorInterface *core) override;
private:
bool m_initialized = false;
QString m_group;
QString m_name;
QString m_includeFile;
Factory m_factory;
};
#endif // KLIPS_WIDGETPLUGIN_H

View File

@@ -1,28 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Collection of widget plugins for Qt Designer ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#include "widgetplugincollection.h"
#include "textview.h"
#include "treeview.h"
#include "widgetplugin.h"
WidgetPluginCollection::WidgetPluginCollection(QObject *parent)
: QObject(parent), m_collectionName("Klips Widget Plugin Collection") {
m_collection = {
new WidgetPlugin(m_collectionName, "Text View Widget", "text-view.h",
[](QWidget *parent) { return new TextView(parent); }),
new WidgetPlugin(m_collectionName, "tree-view",
[](QWidget *parent) { return new TreeView(parent); }),
};
}
QList<QDesignerCustomWidgetInterface *>
WidgetPluginCollection::customWidgets() const {
return m_collection;
}

View File

@@ -1,22 +0,0 @@
#ifndef DESIGNERPLUGINCOLLECTION_WIDGETPLUGINCOLLECTION_H
#define DESIGNERPLUGINCOLLECTION_WIDGETPLUGINCOLLECTION_H
#include <QDesignerCustomWidgetCollectionInterface>
class WidgetPluginCollection : public QObject,
public QDesignerCustomWidgetCollectionInterface {
Q_OBJECT
Q_PLUGIN_METADATA(IID "com.Klips.WidgetPluginCollection")
Q_INTERFACES(QDesignerCustomWidgetCollectionInterface)
public:
explicit WidgetPluginCollection(QObject *parent = nullptr);
[[nodiscard]] QList<QDesignerCustomWidgetInterface *> customWidgets() const;
private:
QList<QDesignerCustomWidgetInterface *> m_collection;
QString m_collectionName;
};
#endif // DESIGNERPLUGINCOLLECTION_WIDGETPLUGINCOLLECTION_H

View File

@@ -1,76 +0,0 @@
################################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Example of making widget plugins for Qt Designer ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
cmake_minimum_required(VERSION 3.15)
project(
#[[NAME]] DesignerPlugin
VERSION 1.0
DESCRIPTION "Example of a widget plugin for Qt Designer"
LANGUAGES CXX
)
include(GenerateExportHeader)
add_compile_options(-Wall)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(CMAKE_SHARED_MODULE_PREFIX "")
set(QT_DIR "$ENV{HOME}/Code/Clones/Qt/" CACHE PATH "Path to Qt6")
# Qt Designer will look in different locations if WIN / Unix.
if (WIN32)
set(QT_PLUGIN_INSTALL_DIR
"${QT_DIR}/Tools/QtCreator/bin/plugins/designer"
)
else()
set(QT_PLUGIN_INSTALL_DIR
"${QT_DIR}/Tools/QtCreator/lib/Qt/plugins/designer"
)
endif()
# This should be set to your Qt6 installation directory.
set(QT_INSTALL_DIR "${QT_DIR}/6.3.1/gcc_64/" CACHE PATH "Path to Qt6 install")
list(APPEND CMAKE_PREFIX_PATH "${QT_INSTALL_DIR}")
find_package(Qt6 REQUIRED COMPONENTS UiPlugin Core Gui Widgets)
# Creating the plugin
qt_add_library(widget-plugin)
target_sources(widget-plugin PRIVATE
text-view.cpp text-view.h
widget-plugin.cpp widget-plugin.h
)
set_target_properties(widget-plugin PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(widget-plugin PUBLIC
Qt::UiPlugin Qt::Core Qt::Gui Qt::Widgets
)
install(TARGETS widget-plugin
RUNTIME DESTINATION "${QT_PLUGIN_INSTALL_DIR}"
BUNDLE DESTINATION "${QT_PLUGIN_INSTALL_DIR}"
LIBRARY DESTINATION "${QT_PLUGIN_INSTALL_DIR}"
)
# Application that will use the widget plugin
qt_add_executable(widget-app
widget-app.cpp widget-app.h widget-app.ui
main.cpp
)
target_link_libraries(widget-app PRIVATE
Qt::Widgets widget-plugin
)

View File

@@ -1,18 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Main driver fprogram for practice using signals and slots in Qt ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#include "widget-app.h"
#include <QApplication>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
WidgetApp widgetApp;
widgetApp.show();
return app.exec();
}

View File

@@ -1,10 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Text viewer for signals and slots examples ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#include "text-view.h"

View File

@@ -1,40 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Text viewer for signals and slots examples ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#ifndef KLIPS_TEXTVIEW_H
#define KLIPS_TEXTVIEW_H
#include <QPlainTextEdit>
class TextView : public QPlainTextEdit {
Q_OBJECT
public:
explicit TextView(QWidget *parent = nullptr) : QPlainTextEdit(parent) { }
~TextView() = default;
public:
signals:
void sendTest();
private:
signals:
void sentTestPrivate();
public slots:
void test() { appendPlainText("Test signal received by TextView."); }
void testArgs(const QString &message) { appendPlainText(message); }
private slots:
void testPrivate() {}
};
#endif // KLIPS_TEXTVIEW_H

View File

@@ -1,16 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Application that uses a custom Qt Designer widget plugin ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#include "widget-app.h"
#include "widget-plugin.h"
WidgetApp::WidgetApp(QWidget *parent) : QMainWindow(parent) {
m_ui = new Ui::MainWindow;
m_ui->setupUi(this);
}

View File

@@ -1,38 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Application that uses a custom Qt Designer widget plugin ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#ifndef KLIPS_WIDGETAPP_H
#define KLIPS_WIDGETAPP_H
#include <QDockWidget>
#include <QMainWindow>
#include <QPlainTextEdit>
#include <QVBoxLayout>
#include <QWidget>
#include "ui_widget-app.h"
class WidgetApp : public QMainWindow {
Q_OBJECT
public:
WidgetApp(QWidget *parent = nullptr);
~WidgetApp() = default;
Ui::MainWindow *m_ui;
public:
signals:
void sendTest();
public slots:
void test(){};
};
#endif // KLIPS_WIDGETAPP_H

View File

@@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="horizontalLayout"/>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>22</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -1,67 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Example Qt Designer widget plugin ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#include "widget-plugin.h"
#include "text-view.h"
#include <QtPlugin>
QString WidgetPlugin::toolTip() const
{
return {};
}
QString WidgetPlugin::whatsThis() const
{
return {};
}
QIcon WidgetPlugin::icon() const
{
return {};
}
bool WidgetPlugin::isContainer() const
{
return false;
}
QString WidgetPlugin::group() const
{
return m_group;
}
QString WidgetPlugin::name() const
{
return QStringLiteral("KlipsWidgetPlugin");
}
QString WidgetPlugin::includeFile() const
{
return QStringLiteral("widget-plugin.h");
}
QWidget *WidgetPlugin::createWidget(QWidget *parent)
{
return new TextView(parent);
}
bool WidgetPlugin::isInitialized() const
{
return m_initialized;
}
void WidgetPlugin::initialize(QDesignerFormEditorInterface *)
{
if (m_initialized)
return;
m_initialized = true;
}

View File

@@ -1,45 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Example Qt Designer widget plugin ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#ifndef KLIPS_WIDGETPLUGIN_H
#define KLIPS_WIDGETPLUGIN_H
#include <QtUiPlugin/QDesignerCustomWidgetInterface>
class WidgetPlugin : public QObject, public QDesignerCustomWidgetInterface {
Q_OBJECT
Q_PLUGIN_METADATA(IID "com.Klips.WidgetPlugin")
Q_INTERFACES(QDesignerCustomWidgetInterface)
public:
explicit WidgetPlugin(QObject *parent = nullptr) : QObject(parent) {}
~WidgetPlugin() = default;
public:
QString group() const override;
QString name() const override;
QString includeFile() const override;
QWidget *createWidget(QWidget *parent) override;
QString toolTip() const override;
QString whatsThis() const override;
QIcon icon() const override;
bool isContainer() const override;
bool isInitialized() const override;
void initialize(QDesignerFormEditorInterface *core) override;
private:
bool m_initialized = false;
QString m_group;
QString m_name;
QString m_includeFile;
};
#endif // KLIPS_WIDGETPLUGIN_H

View File

@@ -1,52 +0,0 @@
################################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Practice project for using Qt Designer with custom C++ widgets ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
cmake_minimum_required(VERSION 3.15)
project(
#[[NAME]] Designer
VERSION 0.1
DESCRIPTION "Practice using Qt designer for desktop applications"
LANGUAGES CXX
)
add_compile_options(-Wall)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(QT_DIR "$ENV{HOME}/Code/Clones/Qt/6.3.1/gcc_64/" CACHE PATH "Path to Qt6")
list(APPEND CMAKE_PREFIX_PATH "${QT_DIR}")
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_add_executable(designer
designer.cpp designer.h designer.ui
debugconsole.h debugconsole.cpp debugconsole.ui
texteditor.h texteditor.cpp texteditor.ui
treeview.h treeview.cpp treeview.ui
main.cpp
)
set_target_properties(designer PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(designer PUBLIC Qt::Core Qt::Gui Qt::Widgets)
install(TARGETS designer
RUNTIME DESTINATION "install/designer"
BUNDLE DESTINATION "install/designer"
LIBRARY DESTINATION "install/designer"
)

View File

@@ -1,18 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Debug console widget made in Qt Designer with C++ ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#include "debugconsole.h"
#include "ui_debugconsole.h"
DebugConsole::DebugConsole(QWidget *parent)
: QDockWidget(parent), ui(new Ui::DebugConsole) {
ui->setupUi(this);
}
DebugConsole::~DebugConsole() { delete ui; }

View File

@@ -1,29 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Debug console widget made in Qt Designer with C++ ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#ifndef DEBUGCONSOLE_H
#define DEBUGCONSOLE_H
#include "ui_debugconsole.h"
#include <QDockWidget>
class DebugConsole : public QDockWidget {
Q_OBJECT
public:
explicit DebugConsole(QWidget *parent = nullptr);
~DebugConsole();
inline QPlainTextEdit *getConsole() { return ui->plainTextEdit; }
private:
Ui::DebugConsole *ui;
};
#endif // DEBUGCONSOLE_H

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DebugConsole</class>
<widget class="QDockWidget" name="DebugConsole">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>DockWidget</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPlainTextEdit" name="plainTextEdit"/>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -1,30 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: MainWindow for Qt Designer desktop application ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#include <QtWidgets>
#include "debugconsole.h"
#include "designer.h"
#include "texteditor.h"
#include "treeview.h"
Designer::Designer(QWidget *parent)
: QMainWindow(parent), designer_(new Ui::Designer) {
designer_->setupUi(this);
setCentralWidget(new TextEditor);
auto debugConsole = new DebugConsole;
debugConsole->getConsole()->appendPlainText("Test 1");
debugConsole->getConsole()->appendPlainText("Test 2");
auto treeView = new TreeView;
addDockWidget(Qt::DockWidgetArea::BottomDockWidgetArea, debugConsole);
addDockWidget(Qt::DockWidgetArea::BottomDockWidgetArea, treeView);
sendTest();
}

View File

@@ -1,39 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: MainWindow for Qt Designer desktop application ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#ifndef KLIPS_SLOTSAPP_H
#define KLIPS_SLOTSAPP_H
#include <QDockWidget>
#include <QMainWindow>
#include <QPlainTextEdit>
#include <QVBoxLayout>
#include <QWidget>
#include "ui_designer.h"
class Designer : public QMainWindow {
Q_OBJECT
public:
Designer(QWidget *parent = nullptr);
~Designer() = default;
public:
signals:
void sendTest();
public slots:
void test(){};
private:
Ui::Designer *designer_;
};
#endif // KLIPS_SLOTSAPP_H

View File

@@ -1,37 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Designer</class>
<widget class="QMainWindow" name="Designer">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget"/>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
</widget>
<addaction name="menuFile"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -1,19 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Main driver program for Qt Designer desktop application.. ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#include "designer.h"
#include <QApplication>
int main(int argc, char * argv[]) {
QApplication app(argc, argv);
Designer qtk;
qtk.show();
// Show widget.
return app.exec();
}

View File

@@ -1,23 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Dockable text editor widget made in Qt Designer with C++ ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#include "texteditor.h"
#include "ui_texteditor.h"
TextEditor::TextEditor(QWidget *parent) :
QDockWidget(parent),
ui(new Ui::TextEditor)
{
ui->setupUi(this);
}
TextEditor::~TextEditor()
{
delete ui;
}

View File

@@ -1,31 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Dockable text editor widget made in Qt Designer with C++ ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#ifndef TEXTEDITOR_H
#define TEXTEDITOR_H
#include <QDockWidget>
namespace Ui {
class TextEditor;
}
class TextEditor : public QDockWidget
{
Q_OBJECT
public:
explicit TextEditor(QWidget *parent = nullptr);
~TextEditor();
private:
Ui::TextEditor *ui;
};
#endif // TEXTEDITOR_H

View File

@@ -1,17 +0,0 @@
<ui version="4.0">
<class>TextEditor</class>
<widget class="QDockWidget" name="TextEditor">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>DockWidget</string>
</property>
<widget class="QWidget" name="dockWidgetContents"/>
</widget>
</ui>

View File

@@ -1,23 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Dockable tree view widget made in Qt Designer with C++ ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#include "treeview.h"
#include "ui_treeview.h"
TreeView::TreeView(QWidget *parent) :
QDockWidget(parent),
ui(new Ui::TreeView)
{
ui->setupUi(this);
}
TreeView::~TreeView()
{
delete ui;
}

View File

@@ -1,31 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Dockable tree view widget made in Qt Designer with C++ ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#ifndef TREEVIEW_H
#define TREEVIEW_H
#include <QDockWidget>
namespace Ui {
class TreeView;
}
class TreeView : public QDockWidget
{
Q_OBJECT
public:
explicit TreeView(QWidget *parent = nullptr);
~TreeView();
private:
Ui::TreeView *ui;
};
#endif // TREEVIEW_H

View File

@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TreeView</class>
<widget class="QDockWidget" name="TreeView">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>DockWidget</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTreeView" name="treeView"/>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -1,50 +0,0 @@
################################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Practice project for using signals and slots in Qt ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
cmake_minimum_required(VERSION 3.15)
project(
#[[NAME]] Slots
VERSION 1.0
DESCRIPTION "Practice using signals and slots in Qt 6"
LANGUAGES CXX
)
add_compile_options(-Wall)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
set(QT_DIR "$ENV{HOME}/Code/Clones/Qt/6.3.1/gcc_64/" CACHE PATH "Path to Qt6")
list(APPEND CMAKE_PREFIX_PATH "${QT_DIR}")
find_package(Qt6 REQUIRED COMPONENTS Core Gui Widgets)
qt_add_executable(slots
text-view.cpp text-view.h
slots-app.cpp slots-app.h
main.cpp
)
set_target_properties(slots PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
)
target_link_libraries(slots PUBLIC Qt::Core Qt::Gui Qt::Widgets)
install(TARGETS slots
RUNTIME DESTINATION "install/slots"
BUNDLE DESTINATION "install/slots"
LIBRARY DESTINATION "install/slots"
)

View File

@@ -1,18 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Main driver fprogram for practice using signals and slots in Qt ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#include "slots-app.h"
#include <QApplication>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
SlotsApp slotsApp;
slotsApp.show();
return app.exec();
}

View File

@@ -1,42 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: MainWindow application for practice using signals and slots in Qt ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#include "slots-app.h"
#include "text-view.h"
SlotsApp::SlotsApp(QWidget *parent) : QMainWindow(parent) {
auto textBox = new QPlainTextEdit;
auto textView = new TextView;
auto frame = new QFrame;
auto dock = new QDockWidget(this);
auto dockWidget = new QWidget;
auto dockWidgetLayout = new QVBoxLayout;
dockWidgetLayout->addWidget(frame);
dockWidgetLayout->addWidget(textBox);
dockWidget->setLayout(dockWidgetLayout);
dock->setWidget(dockWidget);
auto dock2 = new QDockWidget(this);
auto dockWidget2 = new QWidget;
auto dockWidgetLayout2 = new QVBoxLayout;
dockWidgetLayout2->addWidget(textView);
dockWidget2->setLayout(dockWidgetLayout2);
dock2->setWidget(dockWidget2);
textBox->setReadOnly(true);
textBox->appendPlainText("Test 1");
textBox->appendPlainText("Test 2");
addDockWidget(Qt::DockWidgetArea::BottomDockWidgetArea, dock);
addDockWidget(Qt::DockWidgetArea::BottomDockWidgetArea, dock2);
connect(this, &SlotsApp::sendTest, textView, &TextView::test);
sendTest();
}

View File

@@ -1,34 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: MainWindow application for practice using signals and slots in Qt ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#ifndef KLIPS_SLOTSAPP_H
#define KLIPS_SLOTSAPP_H
#include <QDockWidget>
#include <QMainWindow>
#include <QPlainTextEdit>
#include <QVBoxLayout>
#include <QWidget>
class SlotsApp : public QMainWindow {
Q_OBJECT
public:
SlotsApp(QWidget *parent = nullptr);
~SlotsApp() = default;
public:
signals:
void sendTest();
public slots:
void test(){};
};
#endif // KLIPS_SLOTSAPP_H

View File

@@ -1,10 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Text viewer for signals and slots examples ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#include "text-view.h"

View File

@@ -1,40 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
## About: Text viewer for signals and slots examples ##
## ##
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
################################################################################
*/
#ifndef KLIPS_TEXTVIEW_H
#define KLIPS_TEXTVIEW_H
#include <QPlainTextEdit>
class TextView : public QPlainTextEdit {
Q_OBJECT
public:
TextView(QWidget *parent = nullptr) {}
~TextView() = default;
public:
signals:
void sendTest()QWidget;
private:
signals:
void sentTestPrivate();
public slots:
void test() { appendPlainText("Test signal received by TextView."); }
void testArgs(const QString &message) { appendPlainText(message); }
private slots:
void testPrivate() {}
};
#endif // KLIPS_TEXTVIEW_H

View File

@@ -1,11 +0,0 @@
# dotnet
```bash
shaunrd0/klips/dotnet/
├── sitemap # Custom library to generate sitemaps
├── testing # General .NET practice
└── README.md
```
All of these projects were created with the `dotnet` CLI on Linux (Kubuntu 20.04).
They have not been tested on any other platform.

View File

@@ -1,454 +0,0 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET
project.lock.json
project.fragment.lock.json
artifacts/
# Tye
.tye/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
##
## Visual studio for Mac
##
# globs
Makefile.in
*.userprefs
*.usertasks
config.make
config.status
aclocal.m4
install-sh
autom4te.cache/
*.tar.gz
tarballs/
test-results/
# Mac bundle stuff
*.dmg
*.app
# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
# JetBrains Rider
.idea/
*.sln.iml
##
## Visual Studio Code
##
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json

View File

@@ -1,14 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\SiteMapLibrary\SiteMapLibrary.csproj" />
</ItemGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -1,12 +0,0 @@
using SiteMapLibrary;
// Create an XmlManager to use for generating our sitemap; Provide a file path (and optional Xml settings; See ctor)
var mgr = new XmlManager("/home/kapper/Code/klips/dotnet/sitemap/ConsoleApp/TestFiles/sitemap.xml");
// If we want to output the sitemap to the console, instead of saving to a file
// var mgr = new XmlManager("Console.Out");
// Provide a base URL to start crawling, an XmlManager, and a Regex pattern to use for matching URLs while crawling
using SiteMap siteMap = new SiteMap("https://knoats.com", mgr,
new("(http?s://knoats.com(?!.*/dist/|.*/settings/|.*/register/|.*/login/|.*/uploads/|.*/export/|.*/search?).*?(?=\"))"));
// Start crawling; When this returns, we have visited all found URLs and wrote them to our sitemap
await siteMap.Crawl();

View File

@@ -1,9 +0,0 @@
User-agent: *
Disallow:
Disallow: /dist/
Disallow: /settings/
Disallow: /register/
Disallow: /login/
Disallow: /uploads/
Disallow: /export/
Disallow: /search?

View File

@@ -1,975 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<urlset>
<url>
<loc>https://knoats.com</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/tags</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/login</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/shelves</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/c</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/register</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/pi</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/vim</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/git</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/docker</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/ansible</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/security</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/password/email</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/bookstack</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/user/shaun-reed</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/c?shelf=2</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/javascript</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/blockchain</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/networking</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/vim?shelf=1</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/vim?shelf=2</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/git?shelf=2</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/shelves/containers</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/c/page/basics</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/shelves/programming</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/docker?shelf=3</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/docker?shelf=1</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/c/page/classes</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/vim/page/notes</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/ansible?shelf=1</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/git/page/basics</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/game-development</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/pages/recently-updated</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/security?shelf=1</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/bookstack?shelf=3</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/git/chapter/usage</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/networking?shelf=3</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/networking?shelf=1</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/docker/page/gitlab</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/docker/page/shlink</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin?shelf=3</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin?shelf=1</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/git/page/submodules</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/i3</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/networking/page/dns</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/docker/page/heimdall</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/pi/page/installation</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/c-s68/page/dotnet-cli</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/c/page/multithreading</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/grub</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/javascript/page/webgl</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/arch</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/networking/page/tcpip</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/networking/page/nginx</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/link/30#bkmrk-configure-ssl</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/security/page/fail2ban</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/networking/page/apache</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/docker/page/dockerfile</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/git/page/authentication</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/debian</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/networking/page/tcp-udp</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/pages/recently-updated?page=2</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/pages/recently-updated?page=3</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/pages/recently-updated?page=4</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/pages/recently-updated?page=5</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/pi/chapter/magic-mirror</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/pages/recently-updated?page=1</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/self-hosted-applications</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/blockchain/page/solidity</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/c/page/building-projects</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/vim/page/configuring-vim</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/chapter/bash</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/crontab</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/yakuake</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/bookstack/chapter/knoats</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/examples</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/xps-9310</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/wireless</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/security/page/ossec-rules</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/networking/page/osi-model</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/pi/chapter/backup-scripts</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/tunneling</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/networking/page/subnetting</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/bluetooth</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/ansible/page/creating-roles</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/virtualbox</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/security/chapter/monitoring</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/networking/chapter/protocols</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/pi/page/magic-mirror-modules</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/git/page/software-development</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/boot-process</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/shelves/linux-server-administration</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/game-development/page/prefabs</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/networking/page/proxy-servers</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/bookstack/chapter/development</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/game-development/chapter/unity</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/bash-profiles</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/configure-ftp</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/chapter/interfaces</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/audio-devices</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/security/page/server-checklist</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/security/page/devsec-baselines</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/networking/chapter/web-servers</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/bookstack/chapter/installation</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/game-development/page/scripting</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/game-development/page/shortcuts</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/ansible/page/creating-playbooks</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/system-sensors</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/self-hosted-applications?shelf=3</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/swap-allocation</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/getting-started</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/chapter/system-admin</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/server-hostname</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/disk-management</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/pi/page/staging-configs-to-a-usb</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/game-development/page/linux-setup</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/git/page/pushing-merging-branches</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/systemd-services</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/chapter/distributions</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/chapter/customization</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/installing-fonts</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/security/page/virtualbox-networks</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/security/page/ossec-ubuntu-server</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/security/chapter/server-hardening</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/kernel-management</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/ansible/page/managing-remote-hosts</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/configure-postfix</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/self-hosted-applications/page/hexo</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/mount-google-drive</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/self-hosted-applications/page/gitea</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/enabling-google-2fa</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/user-administration</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/unattended-upgrades</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/self-hosted-applications/page/jekyll</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/bookstack/page/welcome-to-knoats-432</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/linux-on-chromebooks</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/game-development/page/post-processing</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/chapter/ssh-configuration</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/bookstack/page/exploring-the-database</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/game-development/page/project-settings</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/game-development/page/new-input-system</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/bookstack/page/bookstack-configuration</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/docker/chapter/docker-compose-services</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/game-development/chapter/unreal-engine-4</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/networking/page/certbot-ssl-certificates</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/yubikey-ssh-authentication</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/self-hosted-applications/page/read-the-docs</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/bookstack/page/backup-bookstack-using-docker</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/game-development/page/gameplay-ability-system</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/synchronizing-time-using-ntp</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/bookstack/page/bookstack-using-docker-compose</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/self-hosted-applications/chapter/url-shortners</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/bookstack/page/updating-bookstack-using-docker</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/configuring-sshd-authentication</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/self-hosted-applications/chapter/site-generators</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/vim/page/configuring-vim#bkmrk-unicode.vim-plugin</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/game-development/page/retarget-skeleton-animations</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/self-hosted-applications/page/mame-web-application</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/linux-admin/page/configuring-multi-boot-filesystems</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
<url>
<loc>https://knoats.com/books/self-hosted-applications/chapter/documentation-generators</loc>
<lastmod>2022-5-4</lastmod>
<changefreq>daily</changefreq>
<priority>0.5</priority>
</url>
</urlset>

View File

@@ -1,45 +0,0 @@
Sitemap generator I created while learning some C#.
Example of using the library is in `ConsoleApp/Program.cs`, files used for testing are in `ConsoleApp/TestFiles/`
`ConsoleApp/TestFiles/sitemap.xml` currently contains the sitemap for my website.
If we run the console application with a different URL that targets this same file, the file will be overwritten with the new sitemap.
There is no need to delete or recreate files manually.
I plan to check for a `robots.txt` while generating sitemaps to prevent crawling pages that aren't useful.
For now there is no use for a `robots.txt`, the `SiteMap.Crawl()` function visits the URL provided to the `SiteMap` constructor.
Regex is used to check the visited page and match URLs with the same base domain, the URLS found are logged for the crawler to visit.
Each time we finish collecting URLS on a page, we move to the next URL in the queue and repeat this process.
Once we finish crawling all URLs, an XML sitemap is generated where the URLs are sorted by their length.
I used [sitemaps.org - XML Format](https://www.sitemaps.org/protocol.html) to determine the proper formatting for the sitemap.
For now, since the web application I used for testing does not respond with [Last-Modified](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Last-Modified) in the HTTP header, the last modified time is set to the date the sitemap was generated.
The `priority` fields are all set to the default value indicated on sitemaps.org, which is `0.5`.
This is to avoid confusing crawlers with a huge list of 'top-priority' pages to crawl.
All `changefreq` fields of the sitemap are marked as `daily`.
The primary motivation for this project was learning about unmanaged resources in C#, and trying out the [Dispose Pattern](https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose?redirectedfrom=MSDN#implement-the-dispose-pattern) for myself.
If someone reading this were to find a problem with the way I handled disposing of the `HttpClient` in the `SiteMap` class, feel free to let me know :) Creating an issue, PR, or sending an email is all acceptable.
### Future plans
* Parse `robots.txt` to avoid crawling pages that are not desired
* Test the generator with an application that serves `LastModified` date; Use it if available
* Set `priority` in a more useful way, or allow some form of customization of the way this is handled.
* Set `changefreq` in a more useful way, or allow some form of customization of the way this is handled.
* Generate a regex pattern to match, if one is not provided
For now, the general use of this library is seen in the example below.
```C#
using SiteMapLibrary;
// Create an XmlManager to use for generating our sitemap; Provide a file path (and optional Xml settings; See ctor)
var mgr = new XmlManager("/home/kapper/Code/klips/dotnet/sitemap/ConsoleApp/TestFiles/sitemap.xml");
// If we want to output the sitemap to the console, instead of saving to a file
// var mgr = new XmlManager("Console.Out");
// Provide a base URL to start crawling, an XmlManager, and a Regex pattern to use for matching URLs while crawling
using SiteMap siteMap = new SiteMap("https://knoats.com", mgr,
new("(http?s://knoats.com(?!.*/dist/|.*/settings/|.*/register/|.*/login/|.*/uploads/|.*/export/|.*/search?).*?(?=\"))"));
// Start crawling; When this returns, we have visited all found URLs and wrote them to our sitemap
await siteMap.Crawl();
```

View File

@@ -1,114 +0,0 @@
using System.Text.RegularExpressions;
namespace SiteMapLibrary;
public class SiteMap : IDisposable
{
private HttpClient _client;
private HashSet<string> _foundUrls;
private HashSet<string> _visitedUrls;
private Queue<string> _visitQueue;
private bool _disposed = false;
private XmlManager XmlManager { get; set; }
public string? Url { get; private set; }
public Regex Regexp { get; set; }
public SiteMap(string url, string savepath, Regex pattern)
{
Url = url;
_client = new HttpClient();
_foundUrls = new HashSet<string>();
_visitedUrls = new HashSet<string>();
_visitQueue = new Queue<string>();
Regexp = pattern;
XmlManager = new XmlManager(savepath);
}
public SiteMap(string url, XmlManager mgr, Regex pattern)
{
_client = new HttpClient();
_foundUrls = new HashSet<string>();
_visitedUrls = new HashSet<string>();
_visitQueue = new Queue<string>();
Regexp = pattern;
Url = url;
XmlManager = mgr;
}
public async Task Crawl()
{
while (Url != null)
{
_visitedUrls.Add(Url);
using var content = await _client.GetAsync(Url);
if (!content.IsSuccessStatusCode)
{
Console.WriteLine($"{content.StatusCode} on url: {Url}");
NextUrl();
continue;
}
var m = Regexp.Match(await content.Content.ReadAsStringAsync());
while (m.Success)
{
foreach (Group group in m.Groups)
{
if (_foundUrls.Add(group.Value))
{
Console.WriteLine(group.Value);
// Console.WriteLine(content.Content.Headers.LastModified);
if (!_visitedUrls.Contains(group.Value) && !_visitQueue.Contains(group.Value))
{
_visitQueue.Enqueue(group.Value);
}
}
}
m = m.NextMatch();
}
NextUrl();
content.Dispose();
}
WriteXml();
}
private void WriteXml()
{
List<string> urls = new List<string>(_visitedUrls.OrderBy(k => k.Length).ToArray());
foreach (string url in urls)
{
XmlManager.AddUrl(url);
}
XmlManager.Save();
}
private void NextUrl()
{
if (_visitQueue.Count == 0)
{
Url = null;
return;
}
Url = _visitQueue.Dequeue();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
_client.Dispose();
}
_disposed = true;
}
}
}

View File

@@ -1,10 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>SiteMap</RootNamespace>
</PropertyGroup>
</Project>

View File

@@ -1,59 +0,0 @@
using System.Xml;
namespace SiteMapLibrary;
public class XmlManager
{
private XmlDocument XmlDocument { get; set; }
private XmlDeclaration XmlDeclaration { get; set; }
private XmlElement XmlUrlset { get; set; }
private string Path { get; set; }
public XmlManager(string path,
string version="1.0", string encoding="utf-8", string standalone="")
{
XmlDocument = new XmlDocument();
XmlDeclaration = XmlDocument.CreateXmlDeclaration(version, encoding, standalone);
XmlDocument.AppendChild(XmlDeclaration);
XmlUrlset = XmlDocument.CreateElement("urlset");
XmlDocument.AppendChild(XmlUrlset);
Path = path;
}
~XmlManager()
{
Save();
}
public void AddUrl(string url)
{
XmlElement newUrl = XmlDocument.CreateElement("url");
XmlUrlset.AppendChild(newUrl);
XmlElement newLoc = XmlDocument.CreateElement("loc");
newLoc.InnerText = url;
newUrl.AppendChild(newLoc);
var lastmod = XmlDocument.CreateElement("lastmod");
lastmod.InnerText = DateTime.Now.Year.ToString()
+ '-' + DateTime.Now.Month.ToString()
+ '-' + DateTime.Now.Day;
newUrl.AppendChild(lastmod);
var changeFreq = XmlDocument.CreateElement("changefreq");
changeFreq.InnerText = "daily";
newUrl.AppendChild(changeFreq);
var priority = XmlDocument.CreateElement("priority");
priority.InnerText = "0.5";
newUrl.AppendChild(priority);
}
public void Save()
{
if (Path == "Console.Out")
{
XmlDocument.Save(Console.Out);
}
else
{
XmlDocument.Save(Path);
}
}
}

View File

@@ -1,28 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30114.105
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SiteMapLibrary", "SiteMapLibrary\SiteMapLibrary.csproj", "{0BDEDA94-7BBF-4F82-9A14-131C4F8A3330}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConsoleApp", "ConsoleApp\ConsoleApp.csproj", "{600802AC-C872-4115-BFE6-DA2AE7138F9C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0BDEDA94-7BBF-4F82-9A14-131C4F8A3330}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0BDEDA94-7BBF-4F82-9A14-131C4F8A3330}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0BDEDA94-7BBF-4F82-9A14-131C4F8A3330}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0BDEDA94-7BBF-4F82-9A14-131C4F8A3330}.Release|Any CPU.Build.0 = Release|Any CPU
{600802AC-C872-4115-BFE6-DA2AE7138F9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{600802AC-C872-4115-BFE6-DA2AE7138F9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{600802AC-C872-4115-BFE6-DA2AE7138F9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{600802AC-C872-4115-BFE6-DA2AE7138F9C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@@ -1,454 +0,0 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET
project.lock.json
project.fragment.lock.json
artifacts/
# Tye
.tye/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
##
## Visual studio for Mac
##
# globs
Makefile.in
*.userprefs
*.usertasks
config.make
config.status
aclocal.m4
install-sh
autom4te.cache/
*.tar.gz
tarballs/
test-results/
# Mac bundle stuff
*.dmg
*.app
# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
# Windows thumbnail cache files
Thumbs.db
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
# JetBrains Rider
.idea/
*.sln.iml
##
## Visual Studio Code
##
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json

View File

@@ -1,13 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\KlipsLibrary\KlipsLibrary.csproj" />
</ItemGroup>
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -1,14 +0,0 @@
using KlipsLibrary;
Klips.SayHello();
int[] arr = { 2, 4, 6, 2, 1, 44, 10 };
Klips.Print(arr);
Console.WriteLine();
HashSet<string> set = new HashSet<string>(){ "hi", "my", "name", "is", "shaun" };
Klips.Print(set);
Console.WriteLine();
// Test other C# containers
Klips.TestContainers();

View File

@@ -1,27 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.11.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.1.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\KlipsLibrary\KlipsLibrary.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,22 +0,0 @@
using Xunit;
namespace KlipsLibrary.Test;
public class UnitTest1
{
[Fact]
public void DogTest()
{
var dog = new Dog("Buford", "Woof");
Assert.Equal("Buford", dog.Name);
dog.Speak();
}
[Fact]
public void HumanTest()
{
var human = new Human("Shaun", "Hi");
Assert.Equal("Shaun", human.Name);
human.Speak();
}
}

View File

@@ -1,70 +0,0 @@
using System.Collections;
using KlipsLibrary;
namespace KlipsLibrary;
public class Solution {
public int NumUniqueEmails(string[] emails)
{
HashSet<string> sent = new();
foreach (var email in emails)
{
var domain = email.Substring(email.IndexOf("@"), email.Length);
var to = email.Substring(0, email.IndexOf("@"));
if (to.Contains(".")) to = to.Replace(".", "");
to = to.Remove(to.IndexOf("+"));
Console.Write("{0} at {1}", to, domain);
sent.Add(to + "@" + domain);
}
return sent.Count;
}
}
public abstract class Animal
{
public Animal(string n, string p)
{
this.Name = n;
this.Phrase = p;
}
public abstract void Speak();
private string name;
public string Name { get; set; }
private string phrase;
public string Phrase { get; set; }
}
public class Dog : Animal
{
public Dog(string n, string p) : base(n, p) { }
public override void Speak()
{
Console.WriteLine("{0} (Dog): {1}", Name, Phrase);
}
}
public class Human : Animal
{
public Human(string n, string p) : base(n, p) { }
public override void Speak()
{
Console.WriteLine("{0} (Human): {1}", Name, Phrase);
}
}
public class Teacher : Human, IComparable, ICloneable
{
public Teacher(string n, string p) : base(n, p) { }
public int CompareTo(object? obj)
{
throw new NotImplementedException();
}
public object Clone()
{
throw new NotImplementedException();
}
}

View File

@@ -1,74 +0,0 @@
namespace KlipsLibrary;
public struct Item : IEquatable<Item>
{
public Item(double v, int q, string name)
{
Value = v;
Qty = q;
Name = name;
}
public Item(double v, string name)
{
Value = v;
Qty = 1;
Name = name;
}
public string Name { get; set; }
public double Value { get; set; }
public int Qty { get; set; }
public static bool operator ==(Item a, Item b)
{
if (((object)a) == null || ((object)b) == null) return Object.Equals(a, b);
return a.Equals(b);
}
public static bool operator !=(Item a, Item b)
{
return !(a == b);
}
public bool Equals(Item other)
{
return Name == other.Name && Value == other.Value;
}
public override bool Equals(object? obj)
{
return obj is Item other && Equals(other);
}
public override int GetHashCode()
{
return HashCode.Combine(Name, Value);
}
}
public class Bag
{
public Bag()
{
contents = new List<Item>();
maxCarry = 10;
}
private List<Item> contents;
private int maxCarry;
public bool AddItem(Item i)
{
if (contents.Count >= maxCarry) return false;
contents.Add(i);
return true;
}
public Item? TakeItem(Item i)
{
var found = contents.Find((Item inBag) => inBag == i);
if (found == default(Item)) return null;
contents.Remove(found);
return found;
}
}

View File

@@ -1,19 +0,0 @@
using System.Collections.ObjectModel;
namespace KlipsLibrary;
public class Fruit
{
public Fruit()
{
Name = "Default";
}
public Fruit(string name)
{
Name = name;
}
public string Name { get; set; }
}
public class Fruits : Collection<Fruit> { }

View File

@@ -1,75 +0,0 @@
namespace KlipsLibrary;
public class A
{
public A()
{
Console.WriteLine("A default constructor was called");
Val = 0;
}
public A(int v)
{
Console.WriteLine("A parameterized constructor was called");
Val = v;
}
private int val;
public int Val
{
// No setter; We can only initialize on construction
init
{
Console.WriteLine($"A.val was initialized: {val}");
val = value;
}
}
}
public class B : A
{
public B()
{
Console.WriteLine("B default constructor was called");
BVal = 0;
}
public B(int bv)
{
Console.WriteLine("B parameterized constructor was called");
BVal = bv;
}
private int bVal;
public int BVal
{
init
{
bVal = value;
Console.WriteLine($"B.bVal was initialized: {bVal}");
}
}
}
public class C : B
{
public C()
{
Console.WriteLine("C default constructor was called");
CVal = 0;
}
public C(int cv)
{
Console.WriteLine("C parameterized constructor was called");
CVal = cv;
}
private int cVal;
public int CVal
{
init
{
cVal = value;
Console.WriteLine($"C.cVal was initialized: {cVal}");
}
}
}

View File

@@ -1,281 +0,0 @@
using System.Collections;
using System.Linq.Expressions;
namespace KlipsLibrary;
public class Klips
{
public static void SayHello()
{
Console.WriteLine("Hello, C# library!");
}
public static void TestInput()
{
string formattingString = "Captured {0} input: {1}\n";
Console.Write("\nInput a character, then press enter: ");
int ascii = Console.Read();
char ch = Convert.ToChar(ascii);
Console.Write(formattingString, "character", ch);
Console.ReadLine(); // Discard any left over input
Console.Write("\nPress a key: ");
ConsoleKeyInfo key = Console.ReadKey();
Console.Write("\n" + formattingString, "key", key.KeyChar);
Console.Write("\nEnter a line: ");
string? line = Console.ReadLine();
Console.Write(formattingString, "line", line);
}
public static void PrintEnum<T>(IEnumerable<T> obj)
{
foreach (var i in obj)
{
Console.Write("{0}, ", i);
}
}
public static void PrintInfo<T>(IEnumerable<T> c)
{
Console.WriteLine("Type: {0}", c.GetType().ToString());
}
public static void Print<T>(IEnumerable<T> obj)
{
Console.WriteLine();
PrintInfo(obj);
PrintEnum(obj);
}
// Doesn't work because we can't resolve passed object name
// + Limited to parameter object name; ref causes errors
public static void PrintName<T>(T obj)
{
Expression<Func<object>> expression = () => obj!;
string name = ((expression.Body as MemberExpression)!).Member.Name;
Console.WriteLine("{0}", name);
}
public static void MakeGarbage(int count)
{
for (int i = 0; i < count; i++)
{
var v = new Version();
}
}
public static void TestContainers()
{
int[] test = { 1, 2, 3, 4, 5 };
Klips.Print(test);
var arr = new int[5];
for (int i = 1; i < 6; i++)
{
arr[i-1] = i;
}
Klips.Print(arr);
var list = new List<int>();
for (int i = 1; i < 6; i++)
{
list.Add(i);
}
Klips.Print(list);
list = list.Concat(arr).ToList();
Klips.Print(list);
list.Sort();
Klips.Print(list);
var dict = new Dictionary<int, string>()
{
[4] = "four",
[2] = "two",
[1] = "one",
[3] = "three",
[5] = "five",
};
Klips.Print(dict);
for (int i = 1; i <= 5; i++)
{
Console.Write("\n{0}", dict[i]);
}
var sortedDict = new SortedDictionary<int, string>(dict);
Klips.Print(sortedDict);
var hashset = new HashSet<int>{3, 1, 4, 2};
Klips.Print(hashset);
var sortedSet = new SortedSet<int>(hashset);
Klips.Print(sortedSet);
var sortedList = new SortedList(sortedDict);
Console.WriteLine("Type: {0}", sortedList.GetType().ToString());
foreach (DictionaryEntry item in sortedList)
{
Console.WriteLine("Key: {0} Value: {1}", item.Key.ToString(), item.Value);
}
// Klips.Print(sortedList);
var q = new Queue<string>(dict.Values);
Klips.Print(q);
var llist = new LinkedList<int>(dict.Keys);
Klips.Print(llist);
}
public static void TestGC()
{
Klips.MakeGarbage(1000000);
// GC.Collect();
Console.Write("\nHeap memory: {0}\nAllocated heap memory: {1}",
GC.GetGCMemoryInfo().HeapSizeBytes.ToString(), GC.GetTotalMemory(false).ToString());
for (int i = 0; i < 3; i++)
{
Console.Write("\nGeneration {0} collection count: {1}", i, GC.CollectionCount(i).ToString());
}
}
public static void TestStrings()
{
Console.Write("\n\nWhat time is it?\n{0}", DateTime.Now.ToString());
var lit = @"
hi
how
""are"" you? \this\is\a\literal
";
Console.WriteLine(lit);
string[] @foreach = {@"\this\is\new\a\test\n", "Not verbatim\nBut still literal"};
foreach (string s in @foreach)
{
Console.WriteLine(@s);
}
string a = "This is my string!";
Console.WriteLine($"This is my rifle; {a, 30}");
Console.WriteLine($"This is {{my}} rifle; {a, -30}");
var b = $"This {{is}} my rifle; {a}";
Console.WriteLine(b);
Console.WriteLine($"Conditional formatting result: {(b.Length == 0 ? "Empty" : "Not empty")}");
var pi = Math.PI;
Console.WriteLine($"{pi:F3}, {pi:F10}, {DateTime.Now:d}, {DateTime.Now:f}, {DateTime.Now.ToLocalTime():h:mm:ss tt zz}");
string fmt = "This is pi: {0}\nThis is the date: {1}\nThis is also pi: {0:F6}";
Console.WriteLine(fmt, Math.PI, DateTime.Now);
}
public static void TestLambdas()
{
// Both of these lambdas are of the same type; Func<string, int> where int is the value returned
var getLen = (string s) => s.Length;
Func<string, int> funcLen = (string s) => s.Length;
Console.WriteLine("Length: {0}", getLen("Hello").ToString());
Console.WriteLine("Length: {0}", funcLen("Hello").ToString());
var isEqual = (string a, string b) => a == b;
Console.WriteLine(isEqual("Test", "Test"));
Func<string, string, bool> funcIsEqual = (string a, string b) => a == b;
Console.WriteLine(funcIsEqual("Test", "Test"));
// These two lamdas are both of type Action<string>, as they do not return a result
var statement = (string s) =>
{
var arr = s.ToCharArray();
Array.Reverse(arr);
Console.WriteLine($"\"{s}\" reversed: {new string(arr)}");
};
Action<string> actionReverse = (string s) =>
{
var arr = s.ToCharArray();
Array.Reverse(arr);
Console.WriteLine($"\"{s}\" reversed: {new string(arr)}");
};
// This lamda is a Func<string, string> as it take a string parameter and returns a string as a result
Func<string, string> revString = (string s) =>
{
var revArr = s.ToCharArray();
Array.Reverse(revArr);
return new string(revArr);
};
string testS = "Racecar";
Console.WriteLine($"{testS} reversed: {revString(testS)}");
statement("Test");
}
public static void TestShape()
{
var shape = new Square();
shape.Print();
var shapeRef = shape;
shapeRef.Height = 20;
shape.Print();
var box = new List<Shape>();
box.Add(new Shape(5, 5));
box.Add(new Square());
box.Last().Width = 8; // Access the last element we added to the List, set its width to 8
box.Add(new Cube());
box.Add(new Rectangle());
box.Add(new Rect());
// Use a lambda to find a Cube, get a reference to it; If we found a Cube, set its depth to 5
if (box.Find((Shape s) => s.GetType() == typeof(Cube)) is Cube cubeRef) cubeRef.Depth = 5;
foreach (var s in box) s.Print(); // Print all the Shapes
var cub = new Cube();
var sqr = cub as Square;
if (sqr != null) sqr.Print();
Console.WriteLine("Testing upcast");
var c = new Cube();
c.Print();
if (c is Square cubeSquare)
{
// Why is Shape's Print() not called?; cubeShape.Print calls Square.Print() instead
var cubeShape = cubeSquare as Shape;
if (cubeShape != null) cubeShape.Print();
}
}
public static void TestBag()
{
var bag = new Bag();
Item wrench = new Item(1.5, 1, "wrench"); // Create a wrench using Item ctor
var spanner = wrench; // Copy wrench to a new item
spanner.Name = "spanner";
spanner.Value = 5.0;
spanner.Qty = 2;
Item socket = new Item(2.5, 5, "socket"); // Create a new item using ctor
bag.AddItem(wrench);
bag.AddItem(spanner);
bag.AddItem(socket);
Item? bagSpanner = bag.TakeItem(spanner);
Console.WriteLine(Object.ReferenceEquals(bagSpanner, spanner));
Item? noSpanner = bag.TakeItem(spanner);
Console.WriteLine(noSpanner == null);
}
public static void TestFruits()
{
Fruits fruits = new Fruits() { new Fruit(), new Fruit("Apple"), new Fruit("Orange")};
foreach (Fruit f in fruits)
{
Console.WriteLine(f.Name);
}
}
public static void TestInitOrder()
{
var aClass = new C(5) {CVal = 10};
}
}

Some files were not shown because too many files have changed in this diff Show More