Assume you did all the proper and mature building steps for your Symfony application. You have a build environment independent of your development environment. You really made sure all the environment variables like `COMPOSER_NO_DEV` and `NODE_ENV` are set correctly without getting the double negatives confused. And you execute `composer`, `yarn`, and whatnot with all the good switches like `--no-dev`, `--frozen-lockfile`, and `--production`. But you still get the following error message: ```text Attempted to load class "WebProfilerBundle" from namespace "Symfony\Bundle\WebProfilerBundle". Did you forget a "use" statement for another namespace? ``` Then you _might_ have forgotten to set `APP_ENV="prod"` on the **production system**. It of course makes sense when you think about it. But it always does, once you figured out. Anyway: I hope this helps a fellow traveler at some point in the future! ❤️


Just a quick blag for my future self: ``` FOR row IN coll FOR entry in doc.array FILTER entry.field_name != @field_name LIMIT @limit RETURN DISTINCT doc ``` Didn't give me what I wanted. While slapping `DISTINCT` on the `RETURN` fixed the problem of "I'm getting the same document over and over again" it now doesn't return `@limit` many documents but seemingly a random — but lower — number. What's actually happening here is, that the indentation is deceiving: the last two lines should be indented one more. ``` FOR row IN coll FILTER POSITION(doc.array[*].field_name , @field_name) == false LIMIT @limit RETURN doc ``` Is what I _actually_ wanted. Edit (2023-04-18): And _now_ I learned that you should actually do this: ``` FOR row IN coll FILTER @field_name NOT IN doc.array[*].field_name LIMIT @limit RETURN doc ```


The official documentation on ArangoDB usage in Symfony is [literally from 2013](https://www.arangodb.com/2013/03/getting-started-with-arangodb-and-symfony-part1/) and hence targeting a pretty old Symfony version. This blag post will cover adding minimal ArangoDB support by hand. The actual database protocol and interacting will be handled by [ArangoDBClient](https://github.com/arangodb/arangodb-php). <a href="https://blag.nullteilerfrei.de/2023/04/04/use-arangodb-in-symfony-without-an-external-bundle/#more-5858" class="more-link">Show me what you've got!</a>


If you want to perform `SOUNDEX` similarity searches with Doctrine in Symfony, you first need to define it as a so called "DQL User Defined Functions". <a href="https://ourcodeworld.com/articles/read/243/how-to-implement-soundex-search-in-mysql-with-doctrine-and-symfony-3">Resources online</a> are a bit dated so I decided to publish this quick blag post. <a href="https://blag.nullteilerfrei.de/2023/01/14/mysql-soundex-function-in-symfony-with-doctrine/#more-5844" class="more-link">That _sounds_ nice, show me more!</a>


When creating invitations to Discord servers – or "guilds" how they seem to called internally – you can configure some limits. For example, you can limit the number of times a link can be used to join a server or you can configure an expiry date. The default setting for the time limit is 7 days btw, which is why most links are expired when you come back to them after some time. I was in the situation that I wanted to invite a limited number of people to a Discord server and each should only receive a link that can only be used once. So in some sense, I wanted to create personalized invite links, which doesn't seem to be a use case that's supported out of the box. <a href="https://blag.nullteilerfrei.de/2022/11/01/use-python-to-generate-discord-invite-ulrs-en-masse/#more-5832" class="more-link">So let's use Python!</a>


I recently played around with scraping public Telegram channels and finally want to do something with the data. In particular, I wanted to play around with Named Entity Recognition (NER) and Sentiment Analysis on the content of the Telegram posts. I think this will probably work much better when you do it for each language separately. So before we answer the question "what's this post about?" or "how angry is the person in the post?", let's answer the question "what language is the post in?" first. And we'll do it while warming up with that hole machine learning (ML) topic. Be aware: I have no idea what I'm doing. <a href="https://blag.nullteilerfrei.de/2022/09/03/machine-learning-for-language-detection-in-python-with-scikit-learn/#more-5811" class="more-link">Do you want to know more?</a>


This blog post will cover my audio setup on Windows. It's core component is called VoiceMeeter which is a virtual audio mixer for Windows developed by Vincent Burel under the company label "VB-Audio". This blog post will focus on the fact that it makes virtual microphones and virtual speakers available which in turn can be used by all program running on your computer. <a href="https://blag.nullteilerfrei.de/2022/07/10/voicemeeter-for-audio-routing-on-windows/#more-5762" class="more-link">Do you want to know more?</a>


**Disclaimer:** If you are not running Windows on your host, you might not get anything out of this post. Sorry Tux. I am convinced that the Windows Sandbox is one of the best virtualization solutions to do dynamic malware analysis (for Windows malware, at least). The reason is quite simple: Distinguishing a Windows 10 Sandbox instance from the actual underlying Windows 10 install should be very difficult for malware. Specifically if the host is running on HyperV with Guarded Host enabled, my current understanding is that there are little to no differences between the two, but they are neatly isolated from one another. The configuration options are limited, but you can easily cook up a config that launches a WindowsSandbox instance that has all the tools you need for some basic unpacking & dynamic analysis. This is what my malware analysis sandbox looks like at launch: <a href="https://blag.nullteilerfrei.de/wp-content/uploads/2021/10/new-windows-sandbox.png"><img fetchpriority="high" decoding="async" src="https://blag.nullteilerfrei.de/wp-content/uploads/2021/10/new-windows-sandbox-300x225.png" alt="New Windows Sandbox" width="300" height="225" class="aligncenter size-medium" /></a> I have successfully executed a number of samples that evade execution in other virtualized environments. That's a far cry from rigorous testing, so take my praise with a grain of salt. Still, it might be worth a try, the setup is really easy. <a href="https://blag.nullteilerfrei.de/2021/10/03/using-windows-sandbox-for-malware-analysis/#more-5728" class="more-link">Do you want to see my config?</a>


(English-only readers can safely ignore this post) I'll be talking at FrOSCon this year again and try to take a stab at a topic that does not _only_ involve technical topics but will also tell the story of a bank heist. This heist wasn't supported by getaway cars and pistols but was solely carried out through cyber-means. The talk is in German though. * Source Code of LaTex Presentation: <a href="https://github.com/larsborn/FrOSCon2021-Ghidra-Bangladesh-Talk" target="_blank" rel="noopener">https://github.com/larsborn/FrOSCon2021-Ghidra-Bangladesh-Talk</a> * Handout PDF: <a href="https://blag.nullteilerfrei.de/wp-content/uploads/2021/08/FrOSConTalk2021-Ghidra-Bangladesh.pdf" target="_blank" rel="noopener">FrOSConTalk2021-Ghidra-Bangladesh</a> * FrOSCon schedule entry: <a href="https://programm.froscon.de/2021/events/2670.html" target="_blank" rel="noopener">https://programm.froscon.de/2021/events/2670.html</a> * Recording on media.ccc: <a href="https://media.ccc.de/v/froscon2021-2670-der_cyber-bankraub_von_bangladesch">https://media.ccc.de/v/froscon2021-2670-der_cyber-bankraub_von_bangladesch</a>


I idly googled for the title and couldn't find code that I can insipidly paste into a console window. So I prepared it here for fellow travelers (and my future self): ```bash wget 'https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_10.0.1_build/ghidra_10.0.1_PUBLIC_20210708.zip' unzip ghidra_10.0.1_PUBLIC_20210708.zip sudo apt install default-jdk ./ghidra/ghidraRun ```


I was writing some Python code that uses [ctypes][] for interfacing with the [Windows ToolHelp API](https://docs.microsoft.com/en-us/windows/win32/api/_toolhelp/). Specifically, I had to [define a Python equivalent][structs] for the [PROCESSENTRY32](https://docs.microsoft.com/en-us/windows/win32/api/tlhelp32/ns-tlhelp32-processentry32) struct. Now, the [ctypes][] [struct definitions][structs] are a little annoying because they do not give you type hints. You can add the type hints _on top_ of the `_fields_` attribute but that looks a little silly because you _literally_ [write everything twice][wet]. In Python 3.7+ ((Starting in Python 3.7, dictionaries keep the insertion order.)), you can solve this using a metaclass, and one stigma of metaclasses is that they have very few applications, so I decided to blog about this one: ```python class FieldsFromTypeHints(type(ctypes.Structure)): def __new__(cls, name, bases, namespace): from typing import get_type_hints class AnnotationDummy: __annotations__ = namespace.get('__annotations__', {}) annotations = get_type_hints(AnnotationDummy) namespace['_fields_'] = list(annotations.items()) return type(ctypes.Structure).__new__(cls, name, bases, namespace) ``` and now you can write: ```python class PROCESSENTRY32(ctypes.Structure, metaclass=FieldsFromTypeHints): dwSize : ctypes.c_uint32 cntUsage : ctypes.c_uint32 th32ProcessID : ctypes.c_uint32 th32DefaultHeapID : ctypes.POINTER(ctypes.c_ulong) th32ModuleID : ctypes.c_uint32 cntThreads : ctypes.c_uint32 th32ParentProcessID : ctypes.c_uint32 pcPriClassBase : ctypes.c_long dwFlags : ctypes.c_uint32 szExeFile : ctypes.c_char * 260 ``` The metaclass simply deduces the `_fields_` attribute of the new class for you before the class is _even created_. It might make sense to think of metaclasses as "class creation hooks", i.e. you get to modify what you have written before the class is actually being defined. The following bit is just to be compatible with [PEP-563](https://www.python.org/dev/peps/pep-0563/): ```python from typing import get_type_hints class AnnotationDummy: __annotations__ = namespace.get('__annotations__', {}) annotations = get_type_hints(AnnotationDummy) ``` And then, the following is the actual magic line: ```python namespace['_fields_'] = list(annotations.items()) ``` This adds the attribute `_fields_` before the class is created. [ctypes]: https://docs.python.org/3/library/ctypes.html [structs]: https://docs.python.org/3/library/ctypes.html#structures-and-unions [wet]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself <a href="https://blag.nullteilerfrei.de/2021/06/20/prettier-struct-definitions-for-python-ctypes/#more-5700" class="more-link">Do you want to know what I was coding?</a>


Assume you have an already running Zabbix instance that is able to send notifications – via e-Mail or Signal for example. The goal of this post is, to use such an instance to get notified whenever there is a new release for a software you may have installed on some of your machines. <a href="https://blag.nullteilerfrei.de/2021/03/25/zabbix-use-low-level-discovery-for-software-update-notifications/#more-5688" class="more-link">Do you want to know more?</a>


Create a new directory in `wp-content/themes` — let's call it `danktheme` in this example. Create two files in that directory: `style.css` and `functions.php` with the following contents: ```css /* Theme Name: Your Themename description: Your Description Author: Your Name Template: twentytwentyone Version: 1.0.0 */ ``` and ```php <?php add_action('wp_enqueue_scripts', 'my_theme_enqueue_styles', 11); function my_theme_enqueue_styles() { wp_enqueue_style('danktheme', get_stylesheet_uri()); } ``` That's it: now you can select "Your Themename" in the admin interface. If you don't want to use `twentytwentyone` as the parent theme — because it's not the most recent one when you read this, for example — replace it in the `style.css`. Yes, in the stylesheet, I'm not making this up, rules are rules.