43 Commits

Author SHA1 Message Date
a3d6a85516 Includes. 2025-03-01 17:08:44 -05:00
a91352ffcd Make Pixel static. 2025-03-01 16:49:15 -05:00
fc0fd98426 Clean up comments. 2025-03-01 16:15:21 -05:00
1a7da67bdb Clean up flush callback. 2025-03-01 15:43:40 -05:00
00ea5dae20 Refactor ownership of draw buffer data. 2025-03-01 10:34:24 -05:00
63899a606a Clean up some comments. 2025-02-26 19:26:53 -05:00
25b4564a8b Fix ESP logging tags. 2025-02-16 14:40:53 -05:00
e2bb406139 Finish cleanup. 2025-02-16 14:32:00 -05:00
96b6a8bec9 Rename project. 2025-02-16 11:48:15 -05:00
509b57fedb Add time_keeper.h
+ Refactor most classes to header only.
2025-02-16 11:24:35 -05:00
75b51f0c7c Cleanup remaining warnings. 2025-02-16 09:41:09 -05:00
74404b1a44 Make TimeKeeper a static member of Display. 2025-02-16 09:12:24 -05:00
9140ba5fb4 Add Timer and TimeKeeper to Display. 2025-02-16 08:58:40 -05:00
c9ec16d70c More cleanup. 2025-02-16 07:25:02 -05:00
5c61fbd378 Clean code. 2025-02-16 06:38:47 -05:00
8636de8f2f Pass RST pin through I2C. 2025-02-15 18:16:25 -05:00
6493988324 Add panel.h, panel.cpp. 2025-02-15 17:52:33 -05:00
64d817e362 Move I2C into header file. 2025-02-15 17:44:58 -05:00
b3d830cdeb Add IPanelDevice. 2025-02-15 17:12:45 -05:00
670a523a16 Clean code. 2025-02-15 14:13:42 -05:00
cc5bffd1e7 Store configs used in ctors. 2025-02-15 10:26:27 -05:00
03784ac097 Move classes to separate files. 2025-02-15 10:11:49 -05:00
9e912048ab Checkpoint adding SSD1306 and PanelDevice. 2025-02-15 09:41:13 -05:00
0743fc4a5e Factor out Panel. 2025-02-14 17:47:44 -05:00
046dfbb6e6 Add Display::set_text. 2025-02-14 17:19:13 -05:00
ef7a027cf0 Factor out I2C. 2025-02-14 16:49:38 -05:00
2dd099f26e Improve ScopedLock. 2025-02-14 16:33:41 -05:00
8aaed133e8 Update Display getters. 2025-02-14 15:58:37 -05:00
58a83590ca Add ScopedLock for LVGL. 2025-02-14 15:50:35 -05:00
dd5335815c Checkpoint 2025-02-14 15:02:49 -05:00
e9d5ef46d1 Replace lcd project 2025-02-13 19:31:58 -05:00
356d8ccd9a WIP debug I2C driver error
E (413) i2c: CONFLICT! driver_ng is not allowed to be used with this old driver
2025-02-09 20:04:25 -05:00
4063921340 Add I2C scanner example. 2025-02-09 11:59:38 -05:00
043fa2fabb WIP lcd 2025-02-09 01:18:06 -05:00
6cd7d7db29 [esp] Port temp-humidity-web example to cmake. 2025-02-08 12:50:06 -05:00
17c559a31f [esp] Add ESP-IDF cmake example. 2025-02-08 12:47:01 -05:00
e6ba60da89 [esp] Add temperature and humidity example. 2025-02-01 23:49:53 -05:00
8bf174d256 [esp] Add ESP examples. 2025-02-01 14:33:40 -05:00
5f9f508581 [cpp] Remove ignores 2022-12-24 10:18:19 -05:00
3b6ecaa5e9 [cpp] Add Qt Desginer widget plugin examples 2022-12-24 10:16:30 -05:00
de652bad32 [cpp] Add catch and qt examples 2022-12-18 08:57:41 -05:00
d1fb33c58e [dotnet] Add dotnet projects and examples
+ Sitemap generator I created while learning the dispose pattern
+ Testing project for learning general C#
2022-05-04 14:59:17 -04:00
6dbac7559a [cpp] Update READMEs for C++ projects and examples 2022-05-04 12:54:06 -04:00
148 changed files with 17181 additions and 25 deletions

2
.gitignore vendored
View File

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

View File

@@ -2,14 +2,16 @@
This repository is a collection of useful code snippets and configurations.
```
github.com/shaunrd0/klips/
```bash
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 or tools I've made
├── README.md
└── scripts # Bash scripts
├── python # Python scripts and tools I've made
├── scripts # Bash scripts
└── README.md
```

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,3 +1,4 @@
# 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.
@@ -72,7 +73,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,9 +21,11 @@ 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(patterns)
add_subdirectory(qt)

View File

@@ -1,21 +1,23 @@
# 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++
├── patterns # Examples of various design patterns written in 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++
├── multithreading # Basic multithreading examples in C++
├── patterns # Examples of various design patterns written in C++
├── qt # Qt project examples using 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
@@ -32,7 +34,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
@@ -61,7 +63,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
@@ -78,5 +80,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.

31
cpp/catch2/CMakeLists.txt Normal file
View File

@@ -0,0 +1,31 @@
################################################################################
## 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

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

View File

@@ -0,0 +1,29 @@
// 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

@@ -0,0 +1,22 @@
################################################################################
## 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)

4
cpp/catch2/src/klips.cpp Normal file
View File

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

View File

@@ -0,0 +1,22 @@
################################################################################
## 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

@@ -0,0 +1,147 @@
#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,6 +15,9 @@ 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)

View File

@@ -0,0 +1,25 @@
# 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
```

24
cpp/qt/CMakeLists.txt Normal file
View File

@@ -0,0 +1,24 @@
################################################################################
## 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)

32
cpp/qt/README.md Normal file
View File

@@ -0,0 +1,32 @@
# 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

@@ -0,0 +1,110 @@
################################################################################
## 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

@@ -0,0 +1,6 @@
#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

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

View File

@@ -0,0 +1,18 @@
/*##############################################################################
## 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

@@ -0,0 +1,10 @@
/*##############################################################################
## 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

@@ -0,0 +1,44 @@
/*##############################################################################
## 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

@@ -0,0 +1,10 @@
/*##############################################################################
## 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

@@ -0,0 +1,36 @@
/*##############################################################################
## 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

@@ -0,0 +1,15 @@
/*##############################################################################
## 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

@@ -0,0 +1,37 @@
/*##############################################################################
## 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

@@ -0,0 +1,107 @@
<?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

@@ -0,0 +1,52 @@
/*##############################################################################
## 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

@@ -0,0 +1,52 @@
/*##############################################################################
## 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

@@ -0,0 +1,28 @@
/*##############################################################################
## 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

@@ -0,0 +1,22 @@
#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

@@ -0,0 +1,76 @@
################################################################################
## 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

@@ -0,0 +1,18 @@
/*##############################################################################
## 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

@@ -0,0 +1,10 @@
/*##############################################################################
## 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

@@ -0,0 +1,40 @@
/*##############################################################################
## 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

@@ -0,0 +1,16 @@
/*##############################################################################
## 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

@@ -0,0 +1,38 @@
/*##############################################################################
## 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

@@ -0,0 +1,33 @@
<?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

@@ -0,0 +1,67 @@
/*##############################################################################
## 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

@@ -0,0 +1,45 @@
/*##############################################################################
## 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

@@ -0,0 +1,52 @@
################################################################################
## 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

@@ -0,0 +1,18 @@
/*##############################################################################
## 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

@@ -0,0 +1,29 @@
/*##############################################################################
## 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

@@ -0,0 +1,26 @@
<?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

@@ -0,0 +1,30 @@
/*##############################################################################
## 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

@@ -0,0 +1,39 @@
/*##############################################################################
## 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

@@ -0,0 +1,37 @@
<?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>

19
cpp/qt/designer/main.cpp Normal file
View File

@@ -0,0 +1,19 @@
/*##############################################################################
## 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

@@ -0,0 +1,23 @@
/*##############################################################################
## 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

@@ -0,0 +1,31 @@
/*##############################################################################
## 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

@@ -0,0 +1,17 @@
<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

@@ -0,0 +1,23 @@
/*##############################################################################
## 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

@@ -0,0 +1,31 @@
/*##############################################################################
## 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

@@ -0,0 +1,26 @@
<?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.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
cpp/qt/side-panel-view.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -0,0 +1,50 @@
################################################################################
## 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"
)

18
cpp/qt/slots/main.cpp Normal file
View File

@@ -0,0 +1,18 @@
/*##############################################################################
## 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

@@ -0,0 +1,42 @@
/*##############################################################################
## 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();
}

34
cpp/qt/slots/slots-app.h Normal file
View File

@@ -0,0 +1,34 @@
/*##############################################################################
## 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

@@ -0,0 +1,10 @@
/*##############################################################################
## 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"

40
cpp/qt/slots/text-view.h Normal file
View File

@@ -0,0 +1,40 @@
/*##############################################################################
## 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

11
dotnet/README.md Normal file
View File

@@ -0,0 +1,11 @@
# 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.

454
dotnet/sitemap/.gitignore vendored Normal file
View File

@@ -0,0 +1,454 @@
## 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

@@ -0,0 +1,14 @@
<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

@@ -0,0 +1,12 @@
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

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

View File

@@ -0,0 +1,975 @@
<?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>

45
dotnet/sitemap/README.md Normal file
View File

@@ -0,0 +1,45 @@
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

@@ -0,0 +1,114 @@
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

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

View File

@@ -0,0 +1,59 @@
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

@@ -0,0 +1,28 @@
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

454
dotnet/testing/.gitignore vendored Normal file
View File

@@ -0,0 +1,454 @@
## 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

@@ -0,0 +1,13 @@
<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

@@ -0,0 +1,14 @@
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

@@ -0,0 +1,27 @@
<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

@@ -0,0 +1,22 @@
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

@@ -0,0 +1,70 @@
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

@@ -0,0 +1,74 @@
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

@@ -0,0 +1,19 @@
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

@@ -0,0 +1,75 @@
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

@@ -0,0 +1,281 @@
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};
}
}

View File

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

View File

@@ -0,0 +1,98 @@
namespace KlipsLibrary;
public class Shape
{
public Shape(int y, int x)
{
Y = y;
X = x;
Name = this.ToString();
}
public Shape()
{
X = 0;
Y = 0;
Name = this.ToString();
}
// Shape position; Private setter, public getter
public int X { get; private set; }
public int Y { get; private set; }
public string Name { get; private set; }
// Auto-implemented properties may use a default value initializer
public virtual int Width { get; set; } = 1;
public virtual int Height { get; set; } = 2;
public virtual void Print()
{
Console.WriteLine($"{Name} WxH is {Width}x{Height} at position ({X},{Y})");
}
}
public class Square : Shape
{
// Set default value on encapsulated value for non auto-implemented properties
private int width = 10;
private int height = 10;
// We can override properties just as we can functions
// + Height and Width properties can no longer set default values
public override int Height
{
// Can use expressions for getters / setters
get => height;
set => width = height = value;
}
public override int Width
{
get => width;
set
{
// Same setter as Height, just within a block of statements
width = value;
height = value;
}
}
public override void Print()
{
Console.WriteLine("Printing Square info...");
base.Print(); // Will use Square's getter / setter to print private int width, height
}
}
public class Cube : Square
{
// Add new properties or encapsulated values as needed
private int depth = 10;
public int Depth
{
get => depth;
set => depth = value;
}
// Implement a `new` Print() function which acts as a new stand-alone implementaton
public new void Print()
{
Console.WriteLine("Printing Cube info...");
Console.WriteLine($"{Name} WxHxD is {Width}x{Height}x{Depth} at position ({X},{Y})");
}
}
public class Rectangle : Shape
{
// Classes that inherit from Rectangle can not override Print
public sealed override void Print()
{
Console.WriteLine("Printing sealed Rectangle info...");
base.Print();
}
}
public class Rect : Rectangle
{
// Rect can't override Print(), since its base class declared it as `sealed`
}

5
dotnet/testing/README.md Normal file
View File

@@ -0,0 +1,5 @@
This is a testing project I created while first learning C#.
There's no objective or goal, aside from playing with different features of C# and NuGet packages.
Essentially, this is a scrap project that I code in while learning new C# things.
Since this is just for learning, I won't bother explaining how to use things here; It's very possible this entire project could disappear one day.

View File

@@ -0,0 +1,34 @@
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}") = "KlipsLibrary", "KlipsLibrary\KlipsLibrary.csproj", "{58CB87C5-7D98-43F9-8AD8-C73766C06E51}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KlipsLibrary.Test", "KlipsLibrary.Test\KlipsLibrary.Test.csproj", "{3576A541-1B1E-42A1-A348-B0CAA3B5BC5A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KlipsConsole", "KlipsConsole\KlipsConsole.csproj", "{A1E88D77-4A17-47BF-BED4-CEB1821FB627}"
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
{58CB87C5-7D98-43F9-8AD8-C73766C06E51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{58CB87C5-7D98-43F9-8AD8-C73766C06E51}.Debug|Any CPU.Build.0 = Debug|Any CPU
{58CB87C5-7D98-43F9-8AD8-C73766C06E51}.Release|Any CPU.ActiveCfg = Release|Any CPU
{58CB87C5-7D98-43F9-8AD8-C73766C06E51}.Release|Any CPU.Build.0 = Release|Any CPU
{3576A541-1B1E-42A1-A348-B0CAA3B5BC5A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3576A541-1B1E-42A1-A348-B0CAA3B5BC5A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3576A541-1B1E-42A1-A348-B0CAA3B5BC5A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3576A541-1B1E-42A1-A348-B0CAA3B5BC5A}.Release|Any CPU.Build.0 = Release|Any CPU
{A1E88D77-4A17-47BF-BED4-CEB1821FB627}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A1E88D77-4A17-47BF-BED4-CEB1821FB627}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A1E88D77-4A17-47BF-BED4-CEB1821FB627}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A1E88D77-4A17-47BF-BED4-CEB1821FB627}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,38 @@
// set pin numbers
const int buttonPin = 4; // the number of the pushbutton pin
const int ledPin = 5; // the number of the LED pin
// variable for storing the pushbutton status
int buttonState = 0;
bool light_on = false;
bool handled = false;
void setup() {
Serial.begin(115200);
// initialize the pushbutton pin as an input
pinMode(buttonPin, INPUT);
// initialize the LED pin as an output
pinMode(ledPin, OUTPUT);
}
void loop() {
// read the state of the pushbutton value
buttonState = digitalRead(buttonPin);
// check if the pushbutton is pressed.
if (buttonState == HIGH) {
if (!handled) {
Serial.println("Handling button pressed.");
light_on = !light_on;
handled = true;
digitalWrite(ledPin, light_on ? HIGH : LOW);
}
// turn LED on
} else {
if (handled) {
Serial.println("Reset button handled state.");
handled = false;
}
}
}

View File

@@ -0,0 +1,9 @@
# 01_led-button
This example is largely adapted from those in [ESP32-basic-starter-kit.pdf](./ESP32-basic-starter-kit.pdf).
The APIs in the original examples paired with this PDF have changed, and I decided to do some different things with the code and/or circuits, but the original code can be [found here](https://www.dropbox.com/scl/fo/6znlij3eb23ih4jxcpv2w/AKvB1t9CCUgoVRVtGen8Yrw?rlkey=z84anl0hs940qf9fpl7l8q8q2&e=1&dl=0).
![schematic](./schematic.png)
Simple LED controlled by an on-board button.

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

View File

@@ -0,0 +1,183 @@
#include <WiFi.h>
//
// Web server project globals
// Replace with your network credentials
const char* ssid = "network-name";
const char* password = "password";
WiFiServer server(80);
// Variable to store the HTTP request
String header;
// Current time
unsigned long currentTime = millis();
// Previous time
unsigned long previousTime = 0;
// Define timeout time in milliseconds (example: 2000ms = 2s)
const long timeoutTime = 2000;
//
// Button / light project globals
// set pin numbers
const int buttonPin = 4; // the number of the pushbutton pin
const int ledPin = 5; // the number of the LED pin
// variable for storing the pushbutton status
int buttonState = 0;
bool light_on = false;
bool handled = false;
void setup() {
Serial.begin(115200);
// initialize the pushbutton pin as an input
pinMode(buttonPin, INPUT);
// initialize the LED pin as an output
pinMode(ledPin, OUTPUT);
// wait for the Serial Monitor to be open
while (!Serial) {
delay(100);
}
// Connect to Wi-Fi network with SSID and password
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// Print local IP address and start web server
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("Web Server IP address: ");
Serial.println(WiFi.localIP());
server.begin();
}
// Handles the on-board button press.
void handleButtonPress() {
// read the state of the pushbutton value
buttonState = digitalRead(buttonPin);
// check if the pushbutton is pressed.
if (buttonState == HIGH) {
if (!handled) {
Serial.println("Handling button pressed.");
light_on = !light_on;
handled = true;
digitalWrite(ledPin, light_on ? HIGH : LOW);
}
// turn LED on
} else {
if (handled) {
Serial.println("Reset button handled state.");
handled = false;
}
}
}
void displayPinState(WiFiClient client, int gpio_pin, bool state) {
// Display current state, and ON/OFF buttons for GPIO <gpio_pin>
client.println(String("<p>GPIO ") + String(gpio_pin) + String(" - Current State ") + String(state ? "ON" : "OFF") + String("</p>"));
// If the output state is off, it displays the ON button
if (state) {
client.println(String("<p><a href=\"/") + String(gpio_pin) + String("/off\"><button class=\"button button2\">OFF</button></a></p>"));
} else {
client.println(String("<p><a href=\"/") + String(gpio_pin) + String("/on\"><button class=\"button\">ON</button></a></p>"));
}
}
void handleStateChange(WiFiClient client, int gpio_pin) {
if (header.indexOf(String("GET /") + String(gpio_pin) + String("/on")) >= 0) {
Serial.println(String("GPIO ") + String(gpio_pin) + String(" on"));
light_on = true;
digitalWrite(gpio_pin, HIGH);
} else if (header.indexOf(String("GET /") + String(gpio_pin) + String("/off")) >= 0) {
Serial.println(String("GPIO ") + String(gpio_pin) + String(" off"));
light_on = false;
digitalWrite(gpio_pin, LOW);
}
}
void loop() {
WiFiClient client = server.available(); // Listen for incoming clients
handleButtonPress();
if (client) { // If a new client connects,
currentTime = millis();
previousTime = currentTime;
Serial.println("New Client."); // print a message out in the serial port
Serial.println("Web Server IP address: ");
Serial.println(WiFi.localIP());
String currentLine = ""; // make a String to hold incoming data from the client
while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected
// Also handle the button press in this loop to not miss events.
handleButtonPress();
currentTime = millis();
if (client.available()) { // if there's bytes to read from the client,
char c = client.read(); // read a byte, then
Serial.write(c); // print it out the serial monitor
header += c;
if (c == '\n') { // if the byte is a newline character
// if the current line is blank, you got two newline characters in a row.
// that's the end of the client HTTP request, so send a response:
if (currentLine.length() == 0) {
// HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
// and a content-type so the client knows what's coming, then a blank line:
client.println("HTTP/1.1 200 OK");
client.println("Content-type:text/html");
client.println("Connection: close");
client.println();
// turns the GPIOs on and off
// Display the HTML web page
client.println("<!DOCTYPE html><html>");
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<link rel=\"icon\" href=\"data:,\">");
// CSS to style the on/off buttons
// Feel free to change the background-color and font-size attributes to fit your preferences
client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
client.println(".button { background-color: #4CAF50; border: none; color: white; padding: 16px 40px;");
client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
client.println(".button2 {background-color: #555555;}</style></head>");
//
// Web Page Heading
client.println("<body><h1>ESP32 Web Server</h1>");
//
// Web Page Body Contents
// Button Controls
displayPinState(client, ledPin, light_on);
//
// Close Web Page Body / Heading
client.println("</body></html>");
// The HTTP response ends with another blank line
client.println();
// Break out of the while loop
break;
} else { // if you got a newline, then clear currentLine
currentLine = "";
}
} else if (c != '\r') { // if you got anything else but a carriage return character,
currentLine += c; // add it to the end of the currentLine
}
}
}
// Clear the header variable
header = "";
// Close the connection
client.stop();
Serial.println("Client disconnected.");
Serial.println("");
}
}

View File

@@ -0,0 +1,15 @@
# 02_led-button-web
This example is largely adapted from those in [ESP32-basic-starter-kit.pdf](./ESP32-basic-starter-kit.pdf).
The APIs in the original examples paired with this PDF have changed, and I decided to do some different things with the code and/or circuits, but the original code can be [found here](https://www.dropbox.com/scl/fo/6znlij3eb23ih4jxcpv2w/AKvB1t9CCUgoVRVtGen8Yrw?rlkey=z84anl0hs940qf9fpl7l8q8q2&e=1&dl=0).
![schematic](./schematic.png)
This example uses the same schematic as [01_led-button](../01_led-button/).
The only difference is that you can also control the button through a web browser from any device connected to your local network.
This example was adapted from the example code in the [Arduino ESP32 API reference](https://docs.espressif.com/projects/arduino-esp32/en/latest/api/wifi.html#wi-fi-ap-example).
![screenshot](./screenshot.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -0,0 +1,161 @@
// Import required libraries
#include "WiFi.h"
#include "ESPAsyncWebServer.h"
#include <Adafruit_Sensor.h>
#include <DHT.h>
// Replace with your network credentials
const char* ssid = "network-name";
const char* password = "password";
#define DHTPIN 4 // Digital pin connected to the DHT sensor
// Uncomment the type of sensor in use:
#define DHTTYPE DHT11 // DHT 11
//#define DHTTYPE DHT22 // DHT 22 (AM2302)
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
DHT dht(DHTPIN, DHTTYPE);
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
String readDHTTemperature() {
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
// Read temperature as Celsius (the default)
float t = dht.readTemperature();
// Read temperature as Fahrenheit (isFahrenheit = true)
//float t = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again).
if (isnan(t)) {
Serial.println("Failed to read from DHT sensor!");
return "--";
}
else {
Serial.println(t);
return String(t);
}
}
String readDHTHumidity() {
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float h = dht.readHumidity();
if (isnan(h)) {
Serial.println("Failed to read from DHT sensor!");
return "--";
}
else {
Serial.println(h);
return String(h);
}
}
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<style>
html {
font-family: Arial;
display: inline-block;
margin: 0px auto;
text-align: center;
}
h2 { font-size: 3.0rem; }
p { font-size: 3.0rem; }
.units { font-size: 1.2rem; }
.dht-labels{
font-size: 1.5rem;
vertical-align:middle;
padding-bottom: 15px;
}
</style>
</head>
<body>
<h2>ESP32 DHT Server</h2>
<p>
<i class="fas fa-thermometer-half" style="color:#059e8a;"></i>
<span class="dht-labels">Temperature</span>
<span id="temperature">%TEMPERATURE%</span>
<sup class="units">&deg;C</sup>
</p>
<p>
<i class="fas fa-tint" style="color:#00add6;"></i>
<span class="dht-labels">Humidity</span>
<span id="humidity">%HUMIDITY%</span>
<sup class="units">&percnt;</sup>
</p>
</body>
<script>
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("temperature").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/temperature", true);
xhttp.send();
}, 10000 ) ;
setInterval(function ( ) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("humidity").innerHTML = this.responseText;
}
};
xhttp.open("GET", "/humidity", true);
xhttp.send();
}, 10000 ) ;
</script>
</html>)rawliteral";
// Replaces placeholder with DHT values
String processor(const String& var){
//Serial.println(var);
if(var == "TEMPERATURE"){
return readDHTTemperature();
}
else if(var == "HUMIDITY"){
return readDHTHumidity();
}
return String();
}
void setup(){
// Serial port for debugging purposes
Serial.begin(115200);
dht.begin();
// Connect to Wi-Fi
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
}
// Print ESP32 Local IP Address
Serial.println(WiFi.localIP());
// Route for root / web page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/html", index_html, processor);
});
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readDHTTemperature().c_str());
});
server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
request->send_P(200, "text/plain", readDHTHumidity().c_str());
});
// Start server
server.begin();
}
void loop(){
}

View File

@@ -0,0 +1,60 @@
# 03_temp-humidity-web
This example is largely adapted from those in [ESP32-basic-starter-kit.pdf](./ESP32-basic-starter-kit.pdf).
The APIs in the original examples paired with this PDF have changed, and I decided to do some different things with the code and/or circuits, but the original code can be [found here](https://www.dropbox.com/scl/fo/6znlij3eb23ih4jxcpv2w/AKvB1t9CCUgoVRVtGen8Yrw?rlkey=z84anl0hs940qf9fpl7l8q8q2&e=1&dl=0).
![schematic](./schematic.png)
Temperature and humidity sensor served on a web page within the local network.
![screenshot](./screenshot.png)
## Dependencies
You need to install a couple of libraries for this project:
* The DHT and the Adafruit Unified Sensor Driver libraries to read from the DHT sensor.
* ESPAsyncWebServer and Async TCP libraries to build the asynchronous web server.
The default Arduino IDE installation will store libraries at `~/Arduino/ibraries` - if this directory doesn't exist, create it.
### Installing DHT Sensor Library
To read from the DHT sensor using Arduino IDE, you need to install the [DHT sensor library](https://github.com/adafruit/DHT-sensor-library).
```bash
wget -O DHT_sensor.zip https://github.com/adafruit/DHT-sensor-library/archive/master.zip
unzip DHT_sensor.zip
mv DHT-sensor-library-master/ ~/Arduino/libraries/DHT_sensor
```
## Install Adafruit Unified Sensor Driver Library
You also need to install the [Adafruit Unified Sensor Driver library](https://github.com/adafruit/Adafruit_Sensor) to work with the DHT sensor.
```bash
wget -O Adafruit_sensor.zip https://github.com/adafruit/Adafruit_Sensor/archive/master.zip
unzip Adafruit_sensor.zip
mv Adafruit_Sensor-master/ ~/Arduino/libraries/Adafruit_sensor
```
## Installing ESPAsyncWebServer Library
Follow the next steps to install the [ESPAsyncWebServer library](https://github.com/me-no-dev/ESPAsyncWebServer):
```bash
wget -O ESPAsyncWebServer.zip https://github.com/me-no-dev/ESPAsyncWebServer/archive/master.zip
unzip ESPAsyncWebServer.zip
mv ESPAsyncWebServer-master/ ~/Arduino/libraries/ESPAsyncWebServer
```
## Installing Async TCP Library
The ESPAsyncWebServer library requires the [AsyncTCP library](https://github.com/me-no-dev/AsyncTCP) to work. Follow the next steps to install that library:
```bash
wget -O AsyncTCP.zip https://github.com/me-no-dev/AsyncTCP/archive/master.zip
unzip AsyncTCP.zip
mv AsyncTCP-master/ ~/Arduino/libraries/AsyncTCP
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

4
esp/cpp/04_esp-idf-arduino/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
build
managed_components
dependencies.lock
sdkconfig.old

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