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).

Local neural networks using ollama

If you wanted to run something like ChatGPT and you have a powerful enough computer, for example with an Nvidia RTX video card, then you can run the ollama project, which will allow you to use one of the ready-made LLM models on a local machine, absolutely free. ollama provides the ability to communicate with LLM models, like ChatGPT, and the latest version also announced the ability to read images, format output data in json format.

I also launched the project on a MacBook with an Apple M2 processor, and I know that the latest models of AMD video cards are supported.

To install on macOS, visit the ollama website:
https://ollama.com/download/mac

Click “Download for macOS”, you will download an archive of the form ollama-darwin.zip, inside the archive there will be Ollama.app which you need to copy to “Applications”. After that, launch Ollama.app, most likely the installation process will occur at the first launch. After that, you saw the ollama icon in the tray, the tray is on the right top next to the clock.

After that, launch a regular macOS terminal and type the command to download, install and launch any ollama model. The list of available models, descriptions, and their characteristics can be found on the ollama website:
https://ollama.com/search

Choose the model with the least number of parameters if it does not fit into your video card at startup.

For example, the commands to launch the llama3.1:latest model:


ollama run llama3.1:latest

Installation for Windows and Linux is generally similar, in one case there will be an ollama installer and further work with it through Powershell.
For Linux, the installation is done by a script, but I recommend using the version of your specific package manager. In Linux, ollama can also be launched through a regular bash terminal.

Sources
https://www.youtube.com/watch?v=Wjrdr0NU4Sk
https://ollama.com