menu

Top 1 deals for Aba Software Software

40
Followers

Get all the best deals that Aba Software has to offer right here on BitsDuJour. Click quick, these discounts don't last long, and we update daily! We have deals on Aba Search and Replace, .

If you Follow Aba Software, you'll get emails when deals go live!

Visit the Aba Software website.

Aba Search and Replace Screenshot
Aba Search and Replace (PC) Discount
for PC

Aba Search and Replace

Easily Perform Global Search and Replace Operations

50% Off
 

Vendor Pulse

The latest news, straight from our vendors.

  • Mar 8 at 2:14pm
    Regex for phone numbers

    Phone numbers in the US and Canada consist of ten digits: a three-digit area code, a three-digit central office code, and a four-digit line number. These components may be separated by dashes, spaces, or dots; the area code is often written in parentheses:

    619-555-0167
    (619) 555-0167
    619.555.0167
    

    There are some limits on the area code:

    • the area code cannot start with 0 or 1 (these digits are used for long-distance calls);
    • the N11 codes are used for special services (most people remember 911 for emergencies);
    • 988 is a suicide crisis helpline.

    Taking these restrictions into account, we can put together this regular expression to match a 10-digit US phone number:

    ^[ \t]*\(?(?!988)[2-9](?!11)\d\d\)?[ .-]?\d{3}[ .-]?\d{4}[ \t]*$
    

    We use a negative lookahead here to skip the N11 codes and 988, so this regex is a bit more fool-proof than other solutions floating on the Internet. For example, it won't match 123-456-7890 or 911-123-4567.

    The [ \t]* part skips optional whitespace before or after the phone number. The regex starts with ^ and ends with $, so it will match the whole string or a line (in multi-line mode). If you want to find phone numbers in the text rather than verify that the string is a phone number, please use \b to match word boundaries:

    \b\(?(?!988)[2-9](?!11)\d\d\)?[ .-]?\d{3}[ .-]?\d{4}\b
    

    Another useful addition to this regex is allowing the initial +1 or 1 for long-distance calling:

    ^[ \t]*(?:\+1 ?|1 ?)?\(?(?!988)[2-9](?!11)\d\d\)?[ .-]?\d{3}[ .-]?\d{4}[ \t]*$
    

    Now the regex also matches:

    +1 619-555-0167
    +16195550167
    1 619-555-0167
    
    Regex for US phone numbers

    International phone numbers consist of a plus sign, a country code (1 to 3 digits), and the national phone number. The total phone number length is limited to a maximum of 15 digits. The minimum length is not specified in the standard, but I found Niue, an island country with a three-digit country code and four-digit national numbers. Five digits are more common, see Tokelau, Tonga, Solomon Islands, or Vanuatu. This gives us the following regex:

    ^[ \t]*\+(?:\d\)?[ .-]?\(?){6,14}\d[ \t]*$
    

    We first match the plus sign, then a digit. After each digit, there can be a closing parenthesis, then a space, dot, or dash, then an opening parenthesis. The last digit is matched separately; the total number of digits is from 7 to 15.

    Restricting the phone number length for each country would be complicated and the numbering plans change sometimes, so I recommend allowing some freedom here.

    The regular expressions above also don't try to balance parentheses; for example, +1 (214 555-0198 would match, but this is rarely a problem.

    Finally, if you want to match either an international phone number or a US/Canadian number, you can combine both regexes:

    ^[ \t]*(?:(?:\+|011 ?)(\d\)?[ .-]?\(?){6,14}\d|\(?(?!988)[2-9](?!11)\d\d\)?[ .-]?\d{3}[ .-]?\d{4})[ \t]*$
    

    In this combined regex, we also allow international phone numbers to start with 011 instead of the plus.

  • Jan 18 at 3:32pm
    On coding with LLMs

    It looks like we are near the peak of the AI mania. The usefulness and the limitations of this technology are clear now. What we see now are attempts to overstretch the idea and apply it where it will never work, much like with blockchain and cryptocurrencies several years ago.

    The ubiquitous AI startups will fail and we will see a decline in stock indexes, as well as a re-evaluation of AI strategies in many companies. I'm not excited about new AI agents, nor scared of becoming irrelevant; I'm bored now. Users are sick of tasteless drawings, trying-to-be-helpful AI summaries, and chat windows popping up from every toaster.

    Please don't get me wrong: there are a lot of areas where LLMs are truly useful. I'm glad that I don't have to write tedious unit tests fully by hand anymore. It's great that you can quickly toss together a throw-away script, translate a function from one programming language to another, or generate something as a starting point when coding in a language that you barely know. The problems arise when you perceive this "something" as a finished product.

    An old book (Code Complete by Steve McConnell) says that writing and reviewing code takes around 30% of an average developer's time. The rest is spent in discussions, replying to emails, reading documentation, troubleshooting, learning, or even personal stuff. The data come from a 1964 research and the proportion certainly depends on the person and the company, but any developer can confirm that they are not working with source code 100% of their time. If we assume the 30% estimate is correct and you can speed up coding by 20%, you can only expect a 5% reduction in the project duration (see Amdahl's law).

    So the promises of creating a complete product in a weekend are unrealistic. Programming is hard. I spend hours debugging UI issues or checking the assembler output and this is my own project coded by hand, so I understand it quite well. If I were vibecoding, it would take more time to find the root cause.

    In my career, I never worked on a project where I would need to generate a lot of mediocre code quickly with an LLM. The usual story goes like this: two Californian guys, working after their day jobs, create a product that suddenly becomes popular. The code is a mess; they hit scalability limits, so they hire a Central European like me because a developer from the Bay Area with the same skills would cost them more; at the same, the salary is higher than what I could earn in my region. So we both tolerate the cultural differences, wild accents, and crazy time zones.

    I gradually debug the issues, make their code better organized and faster. For one company, I managed to make it six times faster. This does not mean that the founders were bad developers; they just cut some corners when creating the first version. But at least, the code was written by a human.

    Many new founders today vibecode, so I think that I will be able to do this job until I die or lose interest. We will see a lot of weird class hierarchies, logical mistakes patched with special case handling, and buggy snippets that the LLM ripped off from GitHub or StackOverflow.

    Less young people will be able to solve technical problems because they will rely on AI when studying. And if you got used to asking ChatGPT for solutions to simple problems, you will never learn how to troubleshoot complex or novel issues that AI cannot help you with. Cognitive skills require training and practice just like physical ones.

    Besides that, prompting is a skill on its own. Sometimes it's easier to write code than to explain verbally in every detail how it should work, especially if English is not your first language.

    I would say that vibecoding only adds another layer of abstraction above high-level programming languages. If your project contains a lot of repetitive AI-generated code, it's a sign that you may benefit from designing a library, a framework, or a DSL (a domain-specific language). Metaprogramming techniques can help in some cases, too.

    As Noam Chomsky noted almost three years ago, LLMs are not a replacement for human mind; they are useful, but cannot think in the way that we do. The mental health impact of AI is under active study now. IMHO, chatting with a video card chip is not something natural for a human being and it certainly creates some information overload. Overall, LLMs don't make software engineering much simpler; they even add complexity when used incorrectly.

    I may add some AI features to Aba Search and Replace in future, but it will never become a privacy-invasive AI agent and your files will always stay on your computer. When developing the app, I only use a locally-running LLM for proofreading texts. No vibecoding, no AI slop. As an experiment, this blog post was written without any help from AI.

  • Jan 11 at 2:33pm
    When msvc::musttail attribute silently fails

    Python developers recently reported a 15% speedup when using the new MSVC musttail attribute to create a threaded interpreter. Unfortunately, I found that MSVC does not always generate a tail call when you use this attribute, which can potentially lead to stack overflow when interpreting a complex program.

    Background

    The musttail attribute, also supported by clang, forces the compiler to generate a tail call for a return statement that calls another function. So instead of a CALL instruction to call this function followed by a RET to return from the current function, it emits a JMP instruction to jump to the next function without creating a new stack frame. MSVC recently added support for this technique, which is useful for p-code interpreters.

    P-code interpreters are traditionally coded as a giant switch statement inside a loop:

    for (each instruction in pcode) {
        switch (opcode) {
            case ADD:
                // do the addition
                break;
            case MUL:
                // do the multiplication
                break;
            ...
        }
    }
    

    The switch statement compiles to an indirect jump. All p-code instructions go through this jump, which makes it hard for the processor to predict the next branch.

    If musttail is supported by your compiler, you can create a function for each p-code instruction and link these functions via a dispatch table:

    function DoAdd(INSTR * instr) {
        // Do the addition
        // ...
        // Move to the next p-code instruction
        instr++;
        return dispatch_table[GetOpcode(instr)](instr); // musttail
    }
    
    function DoMul(INSTR * instr) {
        // Do the multiplication
        // ...
        // Move to the next p-code instruction
        instr++;
        return dispatch_table[GetOpcode(instr)](instr); // musttail
    }
    
    dispatch_table = {
        ADD: DoAdd,
        MUL: DoMul,
        ...
    };
    

    This compiles to an indirect jump in the epilogue of each function. When running your interpreter, the branch predictor will save the branch history separately for each p-code instruction, e.g. if your p-code usually runs MUL after ADD, the processor will remember this. That's why threaded code is usually faster.

    The MSVC problem

    The newly added [[msvc::musttail]] attribute is ignored when the function is moderately complex (so that it saves non-volatile registers on stack) and it has multiple returns (some of them without a tail call):

    void __declspec(noinline) increment(int x) {
        printf("%d\n", x + 1);
    }
    
    void incrementIfPositive(int x) {
        DWORD64 a = GetTickCount64();
        DWORD64 b = GetTickCount64();
        DWORD64 c = GetTickCount64();
        if (c == 0) {
            return;
        }
    
    [[msvc::musttail]]
        return increment(x + (int)(b - a + c / 2));
    }
    

    This is a made-up example, but a similar early return happens in a real interpreter when handling an exception. Assembly output:

    ; 18   :     if (a == 0) {
    
      test  rax, rax
      je    SHORT $LN1@incrementIfPositive
    
    ...
    
    ; 25   :     [[msvc::musttail]]
    ; 26   :     return increment(x + (int)(b - a + c / 2));
    
      shr  rax, 1
      lea  ecx, DWORD PTR [rbx+42]
      sub  eax, edi
      add  ecx, eax
      call ?increment@@YAXH@Z
      mov  rbx, QWORD PTR [rsp+48]
    $LN1@incrementIfPositive:
    
    ; 27   : }
    
      add  rsp, 32          ; 00000020H
      pop  rdi
      ret  0
    ?incrementIfPositive@@YAXH@Z ENDP
    

    Despite the [[msvc::musttail]] attribute, the Visual C++ compiler generates a call to the increment function. I think it’s because the function epilogue is quite long (with add rsp, 32 and pop rdi instructions), so the compiler does not want to duplicate it for the if (c == 0) case. Instead, the compiler generates a conditional jump to $LN1@incrementIfPositive when c == 0, but this prevents the musttail optimization.

    Visual C++ also does not produce any compilation error (as it should do according to the documentation), but just ignores the musttail attribute and generates the call instruction instead of jmp / rex_jmp.

    A workaround that I found is to create a useless handle_exception function and call it instead of returning early:

    int g_x;
    
    void __declspec(noinline) handle_exception(int x) {
        // Do something to avoid optimizing out this function
        g_x = x;
    }
    
    void incrementIfPositive(int x) {
        DWORD64 a = GetTickCount64();
        if (a == 0) {
            return handle_exception(x);
        }
        // The rest of the code is the same
        // ...
    

    Assembly output in this case:

    ; 18   :     if (a == 0) {
    
      test  rax, rax
      jne  SHORT $LN2@incrementIfPositive
    
    ; 27   : }
    
      add  rsp, 32
      pop  rdi
    
    ; 19   :         return handle_exception(x);
    
      jmp  ?handle_exception@@YAXH@Z
    
    ...
    
    ; 24   : 
    ; 25   :     [[msvc::musttail]]
    ; 26   :     return increment(x + (int)(b - a + c / 2));
    
      shr  rax, 1
      lea  ecx, DWORD PTR [rbx+42]
      sub  eax, edi
      add  ecx, eax
      mov  rbx, QWORD PTR [rsp+48]
    
    ; 27   : }
    
      add  rsp, 32
      pop  rdi
    
    ; 24   : 
    ; 25   :     [[msvc::musttail]]
    ; 26   :     return increment(x + (int)(b - a + c / 2));
    
      jmp  ?increment@@YAXH@Z
    ?incrementIfPositive@@YAXH@Z ENDP
    

    Here, a tail call is correctly generated. Unfortunately, this workaround does not help if you have more than one early return from the function. Even if you create several useless functions, it still won't work.

    Conclusion

    I encountered this problem when trying to apply the musttail optimization to the regular expression engine in Aba Search and Replace. I don't know if it affects the Python interpreter, but I reported the bug to Microsoft and it's under their consideration now.

  • Dec 21 2025 at 4:38am
    Mnemonics for hidden controls

    As you may know, you can switch between Windows controls using mnemonics. If you see an underlined character in any Windows application, you can press Alt + this character to set focus to this control or to click a button. For example, in this window, you can press:

    • Alt+D to go to the Decoded JSON Web Token field,
    • Alt+C to click the Copy button, or
    • Alt+F to uncheck the Format JSON option.
    Aba Search and Replace window

    The underlines become visible when you press the Alt key.

    However, if a control is hidden in Win32 (using the ShowWindow function), the mnemonic for it still works. You can still press a hidden button if you know its mnemonic. Imagine you hide a button for unauthorized users, but these users can press it using the Alt+character keyboard shortcut, so this behavior can even create a security vulnerability.

    If your application shows some controls and hides others depending on the state, you may have two controls with the same mnemonic. If one of them is hidden, it may be activated instead of the visible control with the same mnemonic. This happened to me when testing the previous version of Aba Search and Replace.

    The fix is easy: you need to disable a control when you hide it and enable it when you show it. Each ShowWindow call should be paired with an EnableWindow call; you could create a small function that will call both and use it everywhere instead of ShowWindow.

    This quirk applies only to the classic Win32 applications. I've tested with Windows Forms, WPF, and WinUI 3, and you cannot press a hidden button using its mnemonic there. Win32 provides an extra flexibility: you can create a mnemonic that does not correspond to any visible control, but this flexibility is usually not needed and can cause confusion.

  • Sep 7 2025 at 6:25am
    Unix and JavaScript timestamps

    Unix time is the number of seconds elapsed since midnight UTC on January 1, 1970. For example, Unix time was 17‍56684800 on September 1, 2025 at midnight UTC. The counter is independent of the time zone, holding the same value at the same moment in different timezones. It is widely used in C and C++ programming languages, databases (MySQL, PostgreSQL, and SQLite), and file systems (ext3, HFS+, and Reiserfs).

    The counter is typically stored in a 32-bit signed integer, so it can represent dates from December 13, 1901 to January 19, 2038. In 2038, the counter will reach 231−1 and overflow, which is known as the year 2038 problem. Fortunately, most modern implementations have already switched to 64-bit integers.

    Java and JavaScript use the number of milliseconds, not seconds, to represent time since 1970, resulting in a counter with more digits (e.g., 17‍56684800000) that fits in a 64-bit integer. Some other implementations (e.g., Apple File System) count the number of nanoseconds instead.

    The Unix developers chose the epoch of January 1, 1970 because they created the first version of Unix in 1970, so they only needed to represent dates after 1970. Other platforms chose a date close to the introduction of the Gregorian calendar, for example, the Windows counter (the FILETIME structure) starts on January 1, 1601 and the UUID version 1 counter starts on October 15, 1582.

    You can use the following functions in different programming languages to get the current Unix timestamp value:

    • in C/C++, use time_t timestamp = time(NULL);
    • in PHP, use echo time();
    • in Python, use:
    • import time, math
      print(math.ceil(time.time()))
          
    • in JavaScript, use Math.ceil(Date.now() / 1000);
    • in Java, use long timestamp = System.currentTimeMillis() / 1000;
    • in Go, use:
    • import "time"
      timestamp := time.Now().Unix();
      
    • in MySQL, use select unix_timestamp();
    • in PostgreSQL, use select ceil(extract(epoch from current_timestamp));
    • in SQLite, use select strftime('%s');
    Decode Unix timestamp

    Aba Search and Replace can convert Unix/JavaScript timestamps to a date in popular formats including ISO 8601 / RFC 3339, RFC 1123 / RFC 7231, and the Windows system format. It can also perform the reverse conversion and generate the current timestamp.

BitsDuJour is for People who Love Software
Every day we review great Mac & PC apps, and get you discounts up to 100%
Follow Us
© Copyright 2026 BitsDuJour LLC. Code & Design. All Rights Reserved. Privacy Policy