Why I chose WordPress

When I thought about creating my own blog in 2015, I faced the question: which platform to choose? After much searching and comparison, I settled on WordPress. This was not a random choice, but the result of analyzing the platform’s capabilities, its advantages and disadvantages. Today, I would like to share my thoughts and experience using WordPress.

Advantages of WordPress

  • Ease of use
    One of the main reasons why I chose WordPress is its intuitive interface. Even if you have never worked with a CMS before, you can master WordPress in a matter of days.
  • A huge number of plugins
    WordPress provides access to thousands of free and paid plugins. These extensions allow you to add almost any functionality related to blogging, from SEO optimization to social media integration.
  • Scalability
    WordPress is great for blogs of all sizes. Having started with a simple personal blog, I know I can easily grow it by adding new features and functionality.
  • Wide selection of topics
    There are a huge number of free and paid themes available on WordPress that will allow you to create a pretty good looking blog in a short time. Creating a custom design will require the sensitive hand of a designer.
  • SEO-friendly
    WordPress is designed to be search engine friendly by default. Plugins like Yoast SEO make it easy to optimize your content to improve its search rankings.
  • Community and Support
    WordPress has one of the largest communities in the world. If you have a problem, you’ll almost certainly find a solution on forums or blogs dedicated to the platform.
  • Multilingual support
    Thanks to plugins like WPGlobus, I can blog in multiple languages, which is especially important when working with an audience from different countries.

Disadvantages of WordPress

  • Vulnerability to attacks
    WordPress’ popularity makes it a target for hackers. Without proper protection, your site can become a victim of attacks. However, regular updates and installing security plugins help minimize the risks.
  • Plugin Dependency
    Sometimes the functionality you want to add requires installing multiple plugins. This can slow down your blog and cause conflicts between extensions.
  • Performance Issues
    On large blogs, WordPress can start to slow down, especially if many plugins are used. To solve this problem, you need to optimize the database, implement caching, and use a more powerful hosting.
  • Cost of some functions
    While the basic version of WordPress is free, many professional themes and plugins cost money. Sometimes you have to invest to get all the features.

Conclusion

WordPress is a tool that provides the perfect balance between simplicity and power. For me, its advantages outweigh the disadvantages, especially considering the large number of solutions to overcome them. Thanks to WordPress, I was able to create a blog that perfectly suits my needs.

Wordex – speed reading program for iOS

I recently found a speed reading app that I would like to recommend to you.

Speed ​​reading is a skill that can greatly increase your productivity, improve your reading comprehension, and save you time. There are many apps on the market that promise to help you master this skill, but Wordex for iOS stands out among them. In this article, we will tell you what Wordex is, what features it has, who it is suitable for, and why it is worth considering.

What is Wordex?

Wordex is an iOS app designed specifically to develop speed reading skills. It helps users read texts faster, focus on key ideas, and avoid distractions. The program is based on scientific approaches and offers convenient tools to improve reading speed.

Main features of Wordex

  • Speed ​​reading mode: text is displayed in an optimized manner for quick comprehension. Users can adjust the speed of text display depending on their needs.
  • Progress Analysis: The program provides detailed statistics, including reading speed and improvement dynamics. This helps you evaluate your progress and adjust your approach to reading.
  • Text import: Wordex allows you to upload your own texts for practice. You can read articles, books or training materials directly in the application.
  • Intuitive interface: the application is designed in a minimalist style, which makes it easy to use. Even beginners will easily understand the functionality.


Wordex Screenshot 1

Who is Wordex suitable for?

Wordex is ideal for:

  • Students: who need to quickly read course materials and prepare for exams.
  • For businessmen and office workers: who want to process a large amount of information in a minimum amount of time.
  • For readers: who want to read more books and enjoy the process.


Wordex Screenshot 2

Advantages of Wordex

  • Mobility: you can exercise anywhere and anytime thanks to the app on your iPhone or iPad.
  • Personalization: the ability to customize the display of text to suit your needs.


Wordex Screenshot 3

Why try Wordex?

Wordex is not just a tool for learning speed reading. It is a program that develops concentration, expands vocabulary and increases productivity. Once you try Wordex, you will notice how reading stops being a routine and turns into an exciting activity.

Conclusion

If you want to learn speed reading or improve your existing skills, Wordex is a great choice. Easy to use and effective, the app will help you achieve your goals and save valuable time. Download Wordex from the App Store and start practicing today!

AppStore:
https://apps.apple.com/us/app/speed-reading-book-reader-app/id1462633104

Why is DRY important?

There are many articles on the topic of DRY, I recommend reading the original “The Pragmatic Programmer” by Andy Hunt and Dave Thomas. However, I still see many developers having questions about this principle in software development.

The DRY principle states that we must not repeat ourselves, this applies to both code and the processes we perform as programmers. An example of code that violates DRY:

class Client {
    public let name: String
    private var messages: [String] = []
    
    init(name: String) {
        self.name = name
    }
    
    func receive(_ message: String) {
        messages.append(message)
    }
}

class ClientController {
    func greet(client: Client?) {
        guard let client else {
            debugPrint("No client!")
            return
        }
        client.receive("Hello \(client.name)!")
    }

    func goodbye(client: Client?) {
        guard let client else {
            debugPrint("No client!!")
            return
        }
        client.receive("Bye \(client.name)!")
    }
}

As you can see, in the greet and goodbye methods, an optional instance of the Client class is passed, which then needs to be checked for nil, and then work with it can begin. To comply with the DRY method, you need to remove the repeated check for nil for the class instance. This can be implemented in many ways, one option is to pass the instance to the class constructor, after which the need for checks will disappear.

We maintain DRY by specializing ClientController on a single Client instance:

class Client {
    public let name: String
    private var messages: [String] = []
    
    init(name: String) {
        self.name = name
    }
    
    func receive(_ message: String) {
        messages.append(message)
    }
}

class ClientController {
    private let client: Client

    init(client: Client) {
        self.client = client
    }

    func greet() {
        client.receive("Hello \(client.name)!")
    }

    func goodbye() {
        client.receive("Bye \(client.name)!")
    }
}

DRY also concerns the processes that occur during software development. Let’s imagine a situation in which a team of developers has to release a release to the market themselves, distracting them from software development, this is also a violation of DRY. This situation is resolved by connecting a CI/CD pipeline, in which the release is released automatically, subject to certain conditions by the developers.

In general, DRY is about the absence of repetitions both in processes and in code, this is also important due to the presence of the human factor: code that contains less repetitive, noisy code is easier to check for errors; Automated processes do not allow people to make mistakes when performing them, because there is no human involved.

Steve Jobs had a saying, “A line of code you never have to write is a line of code you never have to debug.”

Sources

https://pragprog.com/titles/tpp20/the-pragmatic-programmer-20th-anniversary-edition/
https://youtu.be/-msIEOGvTYM

I will help you with iOS development for Swift or Objective-C

I am happy to announce that I am now offering my services as an iOS developer on Fiverr. If you need help developing quality iOS apps or improving your existing projects, check out my profile:
https://www.fiverr.com/s/Q7x4kb6

I would be glad to have the opportunity to work on your project.
Email: demensdeum@gmail.com
Telegram: https://t.me/demensdeum

Dynamic Linking of Qt Applications on macOS

Today I have released a version of RaidenVideoRipper for Apple devices with macOS and M1/M2/M3/M4 processors (Apple Silicon). RaidenVideoRipper is a quick video editing application that allows you to cut a part of a video file into a new file. You can also make gif, export the audio track to mp3.

Below I will briefly describe what commands I used to do this. The theory of what is happening here, documentation of utilities, can be read at the following links:
https://www.unix.com/man-page/osx/1/otool/
https://www.unix.com/man-page/osx/1/install_name_tool/
https://llvm.org/docs/CommandGuide/llvm-nm.html
https://linux.die.net/man/1/file
https://www.unix.com/man-page/osx/8/SPCTL/
https://linux.die.net/man/1/chmod
https://linux.die.net/man/1/ls
https://man7.org/linux/man-pages/man7/xattr.7.html
https://doc.qt.io/qt-6/macos-deployment.html

First, install Qt on your macOS, also install the environment for Qt Desktop Development. After that, build your project, for example, in Qt Creator, then I will describe what is needed so that dependencies with external dynamic libraries work correctly when distributing the application to end users.

Create a Frameworks directory in the YOUR_APP.app/Contents folder of your application, put external dependencies in it. For example, this is what Frameworks looks like for the RaidenVideoRipper application:

Frameworks
├── DullahanFFmpeg.framework
│   ├── dullahan_ffmpeg.a
│   ├── libavcodec.60.dylib
│   ├── libavdevice.60.dylib
│   ├── libavfilter.9.dylib
│   ├── libavformat.60.dylib
│   ├── libavutil.58.dylib
│   ├── libpostproc.57.dylib
│   ├── libswresample.4.dylib
│   └── libswscale.7.dylib
├── QtCore.framework
│   ├── Headers -> Versions/Current/Headers
│   ├── QtCore -> Versions/Current/QtCore
│   ├── Resources -> Versions/Current/Resources
│   └── Versions
├── QtGui.framework
│   ├── Headers -> Versions/Current/Headers
│   ├── QtGui -> Versions/Current/QtGui
│   ├── Resources -> Versions/Current/Resources
│   └── Versions
├── QtMultimedia.framework
│   ├── Headers -> Versions/Current/Headers
│   ├── QtMultimedia -> Versions/Current/QtMultimedia
│   ├── Resources -> Versions/Current/Resources
│   └── Versions
├── QtMultimediaWidgets.framework
│   ├── Headers -> Versions/Current/Headers
│   ├── QtMultimediaWidgets -> Versions/Current/QtMultimediaWidgets
│   ├── Resources -> Versions/Current/Resources
│   └── Versions
├── QtNetwork.framework
│   ├── Headers -> Versions/Current/Headers
│   ├── QtNetwork -> Versions/Current/QtNetwork
│   ├── Resources -> Versions/Current/Resources
│   └── Versions
└── QtWidgets.framework
    ├── Headers -> Versions/Current/Headers
    ├── QtWidgets -> Versions/Current/QtWidgets
    ├── Resources -> Versions/Current/Resources
    └── Versions

For simplicity, I printed out only the second level of nesting.

Next, we print the current dynamic dependencies of your application:

otool -L RaidenVideoRipper 

Output for the RaidenVideoRipper binary, which is located in RaidenVideoRipper.app/Contents/MacOS:

RaidenVideoRipper:
	@rpath/DullahanFFmpeg.framework/dullahan_ffmpeg.a (compatibility version 0.0.0, current version 0.0.0)
	@rpath/QtMultimediaWidgets.framework/Versions/A/QtMultimediaWidgets (compatibility version 6.0.0, current version 6.8.1)
	@rpath/QtWidgets.framework/Versions/A/QtWidgets (compatibility version 6.0.0, current version 6.8.1)
	@rpath/QtMultimedia.framework/Versions/A/QtMultimedia (compatibility version 6.0.0, current version 6.8.1)
	@rpath/QtGui.framework/Versions/A/QtGui (compatibility version 6.0.0, current version 6.8.1)
	/System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (compatibility version 45.0.0, current version 2575.20.19)
	/System/Library/Frameworks/ImageIO.framework/Versions/A/ImageIO (compatibility version 1.0.0, current version 1.0.0)
	/System/Library/Frameworks/Metal.framework/Versions/A/Metal (compatibility version 1.0.0, current version 367.4.0)
	@rpath/QtNetwork.framework/Versions/A/QtNetwork (compatibility version 6.0.0, current version 6.8.1)
	@rpath/QtCore.framework/Versions/A/QtCore (compatibility version 6.0.0, current version 6.8.1)
	/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit (compatibility version 1.0.0, current version 275.0.0)
	/System/Library/Frameworks/DiskArbitration.framework/Versions/A/DiskArbitration (compatibility version 1.0.0, current version 1.0.0)
	/System/Library/Frameworks/UniformTypeIdentifiers.framework/Versions/A/UniformTypeIdentifiers (compatibility version 1.0.0, current version 709.0.0)
	/System/Library/Frameworks/AGL.framework/Versions/A/AGL (compatibility version 1.0.0, current version 1.0.0)
	/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL (compatibility version 1.0.0, current version 1.0.0)
	/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1800.101.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1351.0.0)

As you can see in RaidenVideoRipper in dependencies Qt and dullahan_ffmpeg. Dullahan FFmpeg is a fork of FFmpeg that encapsulates its functionality in a dynamic library, with the ability to get the current progress of execution and cancel, using C procedures.
Next, replace the paths of the application and all necessary libraries using install_name_tool.

The command for this is:

install_name_tool -change old_path new_path target

Example of use:

install_name_tool -change /usr/local/lib/libavfilter.9.dylib @rpath/DullahanFFmpeg.framework/libavfilter.9.dylib dullahan_ffmpeg.a

After you have entered all the correct paths, the application should start correctly. Check that all paths to the libraries are relative, move the binary, and open it again.
If you see any error, check the paths via otool and change them again via install_name_tool.

There is also an error with dependency confusion, when the library you replaced does not have a symbol in the table, you can check the presence or absence of the symbol like this:

nm -gU path

Once executed, you will see the entire symbol table of the library or application.
It is also possible that you will copy dependencies of the wrong architecture, you can check this using file:

file path

The file utility will show you what architecture a library or application belongs to.

Also, Qt requires the presence of the Plugins folder in the Contents folder of your YOUR_APP.app directory, copy the plugins from Qt to Contents. Next, check the functionality of the application, after that you can start optimizing the Plugins folder by deleting items from this folder and testing the application.

macOS Security

Once you have copied all the dependencies and fixed the paths for dynamic linking, you will need to sign the application with the developer’s signature, and also send a version of the application to Apple for notarization.

If you don’t have $100 for a developer license or don’t want to sign anything, then write instructions for your users on how to launch the application.

This instruction also works for RaidenVideoRipper:

  • Disabling Gatekeeper: spctl –master-disable
  • Allow launch from any sources in Privacy & Security: Allow applications switch to Anywhere
  • Remove quarantine flag after downloading from zip or dmg application: xattr -d com.apple.quarantine app.dmg
  • Check that the quarantine flag (com.apple.quarantine) is missing: ls -l@ app.dmg
  • Add confirm the launch of the application if necessary in Privacy & Security

The error with the quarantine flag is usually reproduced by the error “The application is damaged” appearing on the user’s screen. In this case, you need to remove the quarantine flag from the metadata.

Link to RaidenVideoRipper build for Apple Silicon:
https://github.com/demensdeum/RaidenVideoRipper/releases/download/1.0.1.0/RaidenVideoRipper-1.0.1.0.dmg

Video stabilization with ffmpeg

If you want to stabilize your video and remove camera shake, the `ffmpeg` tool offers a powerful solution. Thanks to the built-in `vidstabdetect` and `vidstabtransform` filters, you can achieve professional results without using complex video editors.

Preparing for work

Before you begin, make sure your `ffmpeg` supports the `vidstab` library. On Linux, you can check this with the command:

bash  
ffmpeg -filters | grep vidstab  

If the library is not installed, you can add it:

sudo apt install ffmpeg libvidstab-dev  

Installation for macOS via brew:

brew install libvidstab
brew install ffmpeg

Now let’s move on to the process.

Step 1: Movement Analysis

First, you need to analyze the video motion and create a file with stabilization parameters.

ffmpeg -i input.mp4 -vf vidstabdetect=shakiness=10:accuracy=15 transfile=transforms.trf -f null -  

Parameters:

shakiness: The level of video shaking (default 5, can be increased to 10 for more severe cases).
accuracy: Analysis accuracy (default 15).
transfile: The name of the file to save the movement parameters.

Step 2: Applying Stabilization

Now you can apply stabilization using the transformation file:

ffmpeg -i input.mp4 -vf vidstabtransform=input=transforms.trf:zoom=5 output.mp4

Parameters:

input: Points to the file with transformation parameters (created in the first step).
zoom: Zoom factor to remove black edges (e.g. 5 – automatically zooms in until artifacts are removed).

Automatic code analysis with Bistr

If you need to analyze the source code of a project, but want to automate this process and use the local power of your computer, the Bistr utility can be a great solution. In this article, we will look at how this utility helps analyze code using the Ollama machine learning model.

What is Bistr?

Bistr is a source code analysis utility that allows you to integrate a local LLM (large language model) model such as Ollama to analyze and process code. With Bistr, you can analyze files in various programming languages ​​such as Python, C, Java, JavaScript, HTML, and more.

Bistr uses the model to check files against specific queries, such as finding an answer to a question about the functionality of the code or a part of it. This provides a structured analysis that helps in developing, testing, and maintaining projects.

How does Bistr work?

  • Load state: When you start an analysis, the utility checks whether the analysis state has been saved previously. This helps you continue where you left off without having to re-analyze the same files.
  • Code Analysis: Each file is analyzed using the Ollama model. The tool sends a request to the model to analyze a specific piece of code. The model returns information about the relevance of the code in response to the request, and also provides a textual explanation of why the given piece is relevant to the task.
  • State Preservation: After each file is parsed, the state is updated to continue with up-to-date information next time.
  • Results output: All analysis results can be exported to an HTML file, which contains a table with a rating of files by relevance, which helps to understand which parts of the code are most important for further analysis.

Installation and launch

To use Bistr, you need to install and run Ollama, a platform that provides LLM models, on your local machine. The Ollama installation instructions for macOS, Windows, and Linux are described below.

Download the latest version of Bistr from git:
https://github.com/demensdeum/Bistr/

After installing Ollama and Bistr, you can start code analysis. To do this, you need to prepare the source code and specify the path to the directory containing the files to be analyzed. The utility allows you to continue the analysis from where you left off, and also provides the ability to export the results in HTML format for easy further analysis.

Example command to run the analysis:


python bistr.py /path/to/code --model llama3.1:latest --output-html result.html --research "What is the purpose of this function?"

In this command:

–model specifies the model to be used for analysis.
–output-html specifies the path to save the analysis results in an HTML file.
–research allows you to ask a question that you want to answer by analyzing the code.

Benefits of using Bistr

  • Local execution: Analysis is performed on your computer without the need to connect to cloud services, which speeds up the process.
  • Flexibility: You can analyze code in different programming languages.
  • Automation: All code analysis work is automated, which saves time and effort, especially when working with large projects.