Arjen Wiersma

A blog on Emacs, self-hosting, Clojure and other nerdy things

The difficulty is going up and down. This day was quite easy in comparison to yesterday. Today it was about parsing some numbers and finding a set of winning numbers.

As I am doing these puzzles in Go I found out that there is no default set type. There is an implementation by HashiCorp named go-set that fills this void. I did not use an external package (I try to avoid them while doing AoC), but I am very tempted to pull that package in.

Here is my solution using lists.

package main

import (
	"fmt"
	"math"
	"strings"

	"arjenwiersma.nl/aoc/internal/aoc"
)

func main() {
	lines := aoc.AsLines("2023/Day04/input.txt")

	ans := 0
	counts := make([]int, len(lines))

	for x := 0; x < len(lines); x++ {
		counts[x] = 1
	}

	for i, l := range lines {
		nums := strings.Split(l, ":")
		parts := strings.Split(nums[1], "|")
		myInts := aoc.StrToInts(strings.Split(parts[1], " "))
		winInts := aoc.StrToInts(strings.Split(parts[0], " "))

		count := 0
		for _, v := range myInts {
			for _, x := range winInts {
				if x == v {
					count += 1
				}
			}
		}
		if count > 0 {
			c := int(math.Pow(2, float64(count)-1))
			for x := 1; x <= count; x++ {
				counts[i+x] += counts[i]
			}
			ans += c
		}
	}
	fmt.Println("Part 1: ", ans)
	ans = 0
	for _, v := range counts {
		ans += v
	}
	fmt.Println("Part 2: ", ans)
}

Day 3 was quite something. I think that in an attempt to make it harder for AI to solve the puzzles the creators also increased the difficulty level of the base puzzles a little too much. The test was not very clear as to what should happen with negative numbers and it might trip people up. The puzzle itself is a great to exercise grid knowledge as you have to work with neighbors and you have to extend the numbers when you find them. Part 2 was just some bookkeeping on my existing implementation, so it was not too much work.

As a note; I first started out with a list of Points, keeping track of the numbers in a coordinate system. This failed miserably :).

package main

import (
	"fmt"

	"arjenwiersma.nl/aoc/internal/aoc"
)

type Point struct {
	Y, X int
}

func IsDigit(b byte) bool {
	return b-'0' >= 0 && b-'0' <= 9
}

func main() {
	lines := aoc.AsLines("2023/Day03/input.txt")

	ygrid := len(lines)
	xgrid := len(lines[0])

	grid := make([][]byte, ygrid)
	for y, l := range lines {
		grid[y] = make([]byte, xgrid)
		for x := 0; x < len(l); x++ {
			grid[y][x] = l[x]
		}
	}

	neighbors := [][]int{
		{-1, -1}, {0, -1}, {1, -1},
		{-1, 0}, {0, 0}, {1, 0},
		{-1, 1}, {0, 1}, {1, 1},
	}

	gears := make(map[Point][]int)
	sum := 0
	for y := 0; y < ygrid; y++ {
		for x := 0; x < xgrid; x++ {
			num := 0
			hasSymbol := false
			isGear := false
			var gearCoord Point
			for IsDigit(grid[y][x]) {
				num = num*10 + int(grid[y][x]-'0')
				for _, n := range neighbors {
					if y+n[1] >= 0 && y+n[1] < ygrid &&
						x+n[0] >= 0 && x+n[0] < xgrid {
						v := grid[y+n[1]][x+n[0]]
						if !IsDigit(v) && v != '.' {
							if v == '*' {
								isGear = true
								gearCoord = Point{X: x + n[0], Y: y + n[1]}
							}
							hasSymbol = true
						}
					}
				}
				x += 1
				if x >= xgrid {
					break
				}
			}
			if num > 0 && hasSymbol {
				if isGear {
					gears[gearCoord] = append(gears[gearCoord], num)
				}
				sum += num
			}
		}
	}

	fmt.Println("Part 1: ", sum) // 498559

	sum = 0
	for _, v := range gears {
		if len(v) == 2 {
			sum += v[0] * v[1]
		}
	}
	fmt.Println("Part 2: ", sum) // 72246648
}

Day 2 was another fun challenge. Lots of splitting of strings. I wonder if there is a better way to filter out the min and max value from the separate grabs.

I am sure I will not be able to complete all challenges this year, but so far so good.

package main

import (
	"fmt"
	"os"
	"strconv"
	"strings"
)

type Grab struct {
	red, green, blue int
}

type Game struct {
	id    int
	grabs []Grab
}

func main() {
	content, _ := os.ReadFile("2023/Day02/input.txt")

	var input []Game
	for g, l := range strings.Split(strings.TrimSpace(string(content)), "\n") {
		game := Game{}
		game.id = g + 1
		parts := strings.Split(l, ":")
		grabs := strings.Split(parts[1], ";")
		for _, h := range grabs {
			grab := Grab{}
			for _, rgb := range strings.Split(h, ",") {
				color := strings.Split(strings.TrimSpace(rgb), " ")
				i, _ := strconv.Atoi(color[0])
				switch color[1] {
				case "red":
					grab.red = i
				case "green":
					grab.green = i
				case "blue":
					grab.blue = i
				}
			}
			game.grabs = append(game.grabs, grab)
		}
		input = append(input, game)
	}

	max := Grab{
		red:   12,
		green: 13,
		blue:  14,
	}

	var possible []Game
outer:
	for _, game := range input {
		for _, grab := range game.grabs {
			if grab.red > max.red || grab.green > max.green || grab.blue > max.blue {
				continue outer
			}
		}
		// fmt.Println("Possible game: ", game)
		possible = append(possible, game)
	}

	sum := 0
	for _, g := range possible {
		sum += g.id
	}
	fmt.Println("Part 1: ", sum)

	var powers []Grab
	for _, game := range input {
		min := Grab{
			red:   0,
			green: 0,
			blue:  0,
		}
		for _, grab := range game.grabs {
			if grab.red > min.red {
				min.red = grab.red
			}
			if grab.green > min.green {
				min.green = grab.green
			}
			if grab.blue > min.blue {
				min.blue = grab.blue
			}
		}
		powers = append(powers, min)
	}

	sum = 0
	for _, x := range powers {
		sum += x.red * x.green * x.blue
	}
	fmt.Println("Part 2: ", sum)
}

The Advent of Code has started again. At NOVI we participate with a group of our students. We use the AoC throughout the entire curriculum as practice exercises to learn new programming languages or the application of data-structures and algorithms.

Day 1 was a tricky start for most people. Part 1 was not too bad, but part 2 tripped most people up. I guess the idea was that you would have to solve the challenge with an array iteration, but most students tripped up. They tried to match each word and replace the occurrence in the text, running head-on into the edge-case where 2 numbers overlap, such as “eightwo”.

Here is my solution using the Go programming language:

package main

import (
	"fmt"
	"os"
	"strings"
	"unicode"
)

func part1(lines []string) {
	ans := 0
	for _, v := range lines {
		var ints []int
		for _, c := range v {
			if unicode.IsDigit(c) {
				ints = append(ints, int(c-'0'))
			}
		}
		if len(ints) == 0 {
			continue
		}
		ans += ints[0]*10 + ints[len(ints)-1]
	}
	fmt.Println("Part 1: ", ans)
}

func part2(lines []string) {
	ans := 0
	for _, v := range lines {
		var ints []int
		for x := 0; x < len(v); x++ {
			for k, val := range []string{"one", "two", "three", "four", "five", "six", "seven", "eight", "nine"} {
				if strings.HasPrefix(v[x:], val) {
					ints = append(ints, k+1)
				}
			}
			if unicode.IsDigit(rune(v[x])) {
				ints = append(ints, int(v[x]-'0'))
			}
		}

		if len(ints) == 0 {
			continue
		}
		ans += ints[0]*10 + ints[len(ints)-1]
	}

	fmt.Println("Part 2: ", ans)
}

func main() {
	content, _ := os.ReadFile("2023/Day01/input.txt")

	lines := strings.Split(string(content), "\n")

	part1(lines)
	part2(lines)
}

As the warm haze of summer gives way to the crisp air of autumn, the season marks a pivotal moment in my academic journey: the commencement of my Master's thesis project. Having successfully had my research proposal accepted earlier this year, I now face the last leg of this marathon—bringing my theoretical framework to life.

The Powerhouse Partnership: Open Universiteit and CWI {#the-powerhouse-partnership-open-universiteit-and-cwi}

While undertaking a Master's thesis is a significant endeavor on its own, I always have to make it more complex. My research will be a collaborative effort between two prominent institutions: the Open Universiteit and the Centrum Wiskunde & Informatica (CWI).

The CWI is not just another research facility; it is a cornerstone in the Dutch digital landscape. It has been the crucible for pioneering advancements that have indelibly shaped our digital world. To name a few highlights, CWI is the hallowed ground where the first-ever internet connection was established, where the Python programming language was conceived, and where countless other groundbreaking technological milestones have taken root. In my venture, I will be joining forces with the SWAT group, a team that specializes in Software Analysis and Transformation.

Introducing “BiDE”: Bridging the Gap Between Code and Visualization {#introducing-bide-bridging-the-gap-between-code-and-visualization}

At the crux of my research is the creation of a novel visual language designed to facilitate intuitive code editing. Dubbed “BiDE”, short for Bidirectional Diagrammatic Editors, this language aims to serve as a transformative tool in how we understand and manipulate code.

Imagine a scenario where you're faced with an enigmatic, complex piece of code—a labyrinth of loops, conditionals, and functions. Traditionally, you would have to painstakingly dissect each line, trying to visualize the underlying architecture mentally. With BiDE, that approach is poised to become a relic of the past. Instead, a streamlined diagrammatic representation of the code will pop up, offering you a high-level overview.

What sets BiDE apart is its bidirectional functionality. Not only can you comprehend the structure of the code through its visual depiction, but you can also make edits either in the diagrammatic interface or the source code. The brilliance lies in their synchrony; changes in one environment are automatically reflected in the other, keeping both up-to-date in real-time.

A Journey of Discovery, Planning, and Adaptation {#a-journey-of-discovery-planning-and-adaptation}

As I've begun work on my thesis, I've quickly noticed that the process is surprisingly open-ended. Aside from regular meetings with my supervisor, there's not much of a predefined structure. This makes the ability to plan and organize my work even more crucial than before. Without a strong framework, it's easy to get lost in the complexity of the project. So, while the flexibility offers a lot of freedom, it also comes with the responsibility to be my own taskmaster, making sure each piece of the puzzle fits just right.

Staying Connected {#staying-connected}

As I move forward, I will update you on the developments, challenges, and breakthroughs of this endeavor.

Working on my thesis research proposal has been quite the journey, and not always in the direction I would have chosen. A personal revelation that struck me during the process is the tight and rather vexing relationship between perfectionism, procrastination, and paralysis.

It's often said that the perfect is the enemy of the good. In my quest for the 'just right' words to articulate my thoughts, I found this saying to be glaringly accurate. The ticking clock became a dull backdrop to my cerebral scavenger hunt. My concentration started to drift and instead of zeroing in on my research proposal, I found myself fixated on, of all things, the color scheme of my desktop environment.

I got tangled up in a fascinating yet peculiar rabbit hole – the slightly discordant appearance of my Emacs compared to my i3 top bar. This, of course, necessitated immediate rectification, just as I was contemplating that elusive sentence. I spent the entire evening indulging in the color-coded symphony of Catppuccin. Updating the aesthetic of my terminal, tmux, Emacs, Firefox, and i3 configuration was a strange kind of thrill. By the end, I had a beautifully cohesive desktop environment. And yet, that pesky sentence still hung in the air, unwritten.

{{< figure src=“/ox-hugo/catppuccin.png” >}}

Dr. Karen McDowell, a noted advocate for mental wellness, hits the nail on the head when she says, “When you tackle perfectionism, you’re less likely to procrastinate.” Her wisdom tells us that striving for flawlessness not only impedes our progress but also mars the satisfaction we derive from our achievements.

So, how do we break free from this perfection-procrastination paralysis? Dr. McDowell offers a straightforward, seven-step plan:

  1. Consciously lower the bar: Acknowledge that it's okay not to be perfect.
  2. Keep your tasks bite-sized: Manageable chunks are less daunting.
  3. Track your time: Understand where your hours are going.
  4. Surround yourself with positive support: Encouragement helps to keep your spirits high.
  5. Practice saying ‘no’: Respect your capacity and set boundaries.
  6. Use the reward system: Motivate yourself with small incentives.
  7. Incorporate mindfulness: Stay in the present and appreciate your progress.

Now, bear in mind, trying to implement all these changes at once might be a bit like swallowing an elephant whole – impossible and frankly quite unpleasant. The key is to choose a few steps to begin with and gradually incorporate the others. For me, steps one to three seem like a good starting point.

As I venture on this path, I hope to transform my approach towards work, shedding the weight of perfection and embracing the joy of creation. And perhaps, in doing so, I might finally write that sentence.

#mental #health

Using AI, in particular generative models such as GPT, are in contention within academics. The purity of academics resides in students writing on their research and having their work peer-reviewed. But how can you now be sure that the student wrote the paper and how can you trust its content? Many universities, including the OU have written about it. The OU published an article in Modulair about it. Generally, the consensus seems to be that it is ok to use AI as an assistant, but you must write your texts.

For me AI has proven to be a valuable assistant. Here are some ways in which I found AI to be extremely useful:

Blank page syndrome {#blank-page-syndrome}

“Blank page syndrome” refers to the common experience of feeling stuck and overwhelmed when faced with a blank document. It can hinder productivity and creativity in academic writing. Thankfully, AI-powered tools have been developed to combat this syndrome. Utilizing natural language processing algorithms, these tools can generate ideas, provide content suggestions, and even create outlines to jumpstart the writing process. Examples of such tools include ChatGPT and LLaMA, which have proven to be invaluable resources for overcoming this challenge.

Take the following, simplified, prompt:

I am writing a blog post on using AI to write academic papers. I want to cover “blank page syndrome”, “finding related works” and “spelling and grammar correction”. Your task is to work as my writing assistant. Write an outline for this article.

Results in the following outline:

I. Introduction
A. Brief explanation of the challenges faced in academic writing
B. Introduction to the role of AI in overcoming these challenges

II. Understanding "Blank Page Syndrome"
A. Definition and common experiences associated with "blank page syndrome"
B. Causes and psychological factors contributing to the syndrome
C. Introduction to AI-powered tools that can help combat it

III. Overcoming "Blank Page Syndrome" with AI
A. AI-based content generation tools
1. Natural language processing algorithms for generating ideas
2. Examples of AI tools that provide content suggestions and outlines

IV. Finding Related Works Efficiently
A. Importance of literature review and related work in academic writing
B. Challenges in finding relevant sources and connections
C. AI-driven approaches to streamline the process
1. Text mining and semantic analysis algorithms
2. Machine learning techniques for identifying related works
D. Examples of AI tools for efficient literature search and recommendation

V. Improving Spelling and Grammar Accuracy
A. Significance of proper spelling and grammar in academic papers
B. Limitations of traditional spell checkers and grammar tools
C. AI-powered proofreading tools for enhanced accuracy
1. Natural language processing algorithms for grammar checks
2. Machine learning models for spelling and punctuation correction
D. Examples of popular AI-based writing assistant tools

VI. Ethical Considerations and Human Oversight
A. Discussing concerns regarding overreliance on AI in writing
B. Importance of human oversight and critical thinking
C. Addressing potential biases and limitations in AI-driven writing tools

VII. Benefits and Impact of AI in Academic Writing
A. Increased productivity and efficiency for researchers
B. Enhanced accuracy and clarity in written work
C. Facilitation of interdisciplinary research and collaboration

VIII. Future Possibilities and Challenges
A. Advancements in AI technologies for academic writing
B. Integration of AI into existing writing platforms and workflows
C. Challenges and considerations for the future of AI in academic writing

IX. Conclusion
A. Recap of the benefits of using AI in academic writing
B. Encouragement for researchers to explore and utilize AI tools
C. Final thoughts on the transformative potential of AI in academic writing

Make sure to expand on each section with relevant examples, case studies, and practical tips to provide a comprehensive understanding of how AI can assist in academic writing.

How is that for a starter outline? Yes, you will have to work on the structure and the ideas, but you get to start with a solid base. It frees you from the initial “get it on paper” anxiety.

Conducting a comprehensive literature review and identifying relevant related works is crucial for academic writing. However, this task can be time-consuming and overwhelming. AI-driven approaches have emerged to streamline the process and provide researchers with efficient ways to discover related works. By leveraging text mining, semantic analysis, and machine learning techniques, AI tools can analyze vast databases of scholarly articles, uncover hidden connections, and recommend relevant sources. Tools like scite_'s Assistant (https://scite.ai/assistant) have proven to be invaluable assets for researchers, enabling them to save time and access a wealth of knowledge with ease.

{{< figure src=“/ox-hugo/scite-assistant.png” >}}

Improving spelling and grammar accuracy {#improving-spelling-and-grammar-accuracy}

Accurate spelling and proper grammar are essential in academic writing to effectively convey ideas. While traditional spell checkers and grammar tools have limitations, AI-powered proofreading tools have significantly improved accuracy and efficiency. These tools leverage natural language processing algorithms and machine learning models to identify grammar mistakes, spelling errors, and punctuation inconsistencies. Grammarly, a widely recognized tool, has gained acclaim for its ability to enhance the overall quality of written work, ensuring polished and error-free academic papers.

{{< figure src=“/ox-hugo/grammarly.png” >}}

Ethical Considerations and Human Oversight {#ethical-considerations-and-human-oversight}

While AI tools provide invaluable assistance, it's important to acknowledge the importance of human oversight and critical thinking in academic writing. Researchers should exercise caution and verify the suggestions provided by AI tools. Additionally, addressing potential biases and limitations in AI-driven writing tools is crucial to ensure fair representation and accurate information.

Benefits and Impact of AI in Academic Writing {#benefits-and-impact-of-ai-in-academic-writing}

The integration of AI into academic writing processes holds tremendous potential. Researchers can benefit from increased productivity, as AI tools expedite tasks that would otherwise be time-consuming. The enhanced accuracy and clarity in written work contribute to improved quality, enabling researchers to convey their ideas more effectively. Moreover, AI-powered tools facilitate interdisciplinary research, knowledge dissemination, and collaboration, breaking down barriers and fostering innovation across academic disciplines.

Future Possibilities and Challenges {#future-possibilities-and-challenges}

The future of AI in academic writing looks promising. Advancements in AI technologies, including more sophisticated natural language processing algorithms and intelligent content generation models, will further enhance the capabilities of AI tools. Integrating AI into existing writing platforms and workflows will streamline the academic writing process, making it more accessible and user-friendly. However, challenges such as addressing

Conclusion {#conclusion}

In conclusion, the utilization of AI tools in academic writing can have a transformative impact on researchers. By leveraging AI-powered text generation and proofreading capabilities, academics can experience a multitude of benefits. Firstly, AI tooling allows for increased writing velocity, enabling researchers to produce content more efficiently. With AI's assistance, the time-consuming process of meticulously correcting spelling and grammar errors is significantly reduced, freeing up valuable time for researchers to focus on the critical thinking process. As a result, the overall quality of written work can be elevated, ensuring that ideas are effectively conveyed and scholarly contributions are of the highest standard. By embracing AI tooling, academics can embrace a more streamlined and effective approach to writing, empowering them to make significant strides in their research endeavors.

{{< figure src=“/ox-hugo/chatgpt-ai-conclusion.png” >}}

Today, I took the first step towards starting my master's thesis. I have decided to document my journey and experiences on my blog. Given that the thesis will play a pivotal role in my life for the next nine months, I expect it to be a thrilling journey.

Finding a topic {#finding-a-topic}

As a student at Open Universiteit in The Netherlands, I had the opportunity to work with the Rascal programming language during the Software Quality Management course. I found the language intriguing and enjoyed working with it throughout the module. After consulting with my professor, we brainstormed various possibilities for my master's thesis topic, ultimately settling on the creation of a visualization library for the language.

Although I had to complete my Software Architecture course before embarking on my thesis, I finally had the chance to visit the Center for Mathematics and Informatics (CWI), an important organization in the Netherlands. The CWI has a large department devoted to quantum computing and is responsible for developing and maintaining the Rascal programming language, in addition to being the first entity to connect to the internet and register a “.nl” domain name. Oh, and it is also the place where Python was invented. During my visit, we discussed a plethora of options, including reusable components and compositional visualizations, but ultimately decided to focus on projectional editors.

Projectional editors are a type of text editor that allows users to work with a representation of the code's abstract syntax tree (AST), instead of working with the code directly. This approach enables users to work with a higher-level representation of the code, which can make it easier to comprehend and manipulate complex code structures. Typically, users create and edit code in projectional editors by selecting elements from a palette or menu and positioning them in a visual representation of the code's syntax tree. The editor then automatically generates the corresponding code based on the user's selections. This approach is especially useful for languages with intricate syntax or when developing domain-specific languages.

To create a visualization of source code in the form of a diagram, a domain-specific language (DSL) is required to describe the visualization. A DSL is a programming language designed to solve problems in a specific domain or context. In this case, a DSL would be used to describe the structure and layout of the visualization of the source code.

Currently, there is no existing DSL that can be used to describe the visualization of source code. Therefore, as part of the master's thesis, the focus will be on creating a context-free grammar (CFG) capable of generating the DSL required for the visualization. The CFG will define the syntax and structure of the language, including the rules and patterns used to create the visual representation of the code.

Once the CFG is created, the DSL can be generated and used to create the visualization of the source code in the form of a diagram. This visualization will enable users to reason about their code in a high-level manner, helping to identify and understand complex code structures and relationships.

Context-Free Grammars {#context-free-grammars}

A context-free grammar (CFG) is a formalism used to describe the syntax of a formal language. A CFG consists of a set of rules that define how strings of symbols can be constructed in the language. The rules in a CFG specify how non-terminal symbols can be replaced with sequences of terminal and non-terminal symbols.

A non-terminal symbol represents a syntactic category or type of element in the language, while a terminal symbol represents a basic unit of meaning or a symbol that cannot be further reduced. The rules in a CFG define how non-terminal symbols can be replaced by sequences of terminal and non-terminal symbols, and how these sequences can be combined to form valid strings in the language.

Consider the following CFG:

S -> aSb | ε

In this CFG, S is a non-terminal symbol that represents a string of the form a^n b^n where n >= 0. The rule S -> aSb specifies that a string of the form a^n b^n can be constructed by taking a string of the form a^(n-1) b^(n-1) and appending an a to the beginning and a b to the end. The rule S -> ε specifies that the empty string is also a valid string of the language.

Using this CFG, we can generate the following strings:

ε
ab
aabbb
aaabbbb
aaaabbbbb

To generate the string aaaabbbbb, we can use the following sequence of derivations:

S => aSb          (apply rule S -> aSb)
  => aaSbb        (apply rule S -> aSb)
  => aaaSbbb      (apply rule S -> aSb)
  => aaaaSbbbb    (apply rule S -> aSb)
  => aaaabbbbb    (apply rule S -> ε)

Note that at each step in the derivation, we apply a rule to replace a non-terminal symbol with a sequence of terminal and non-terminal symbols, until we arrive at a string composed entirely of terminal symbols (i.e., the empty string or a string of the form a^n b^n).

Moving forward {#moving-forward}

The preparation phase for the master's thesis at Open Universiteit spans 11 weeks, followed by 22 weeks of research and writing. As I am just starting the preparation phase, I anticipate the topic to evolve over time, and I look forward to sharing my journey with you.

#education

Background {#background}

I have been working on getting my Master's degree in Software Engineering. To do this I have started following courses at the Dutch Open Universiteit. They have a Master's program that takes 2 years and you are able to follow it from home.

As this is my first post on the courses, I will give some background. As a teacher it is recommended to have a Master's degree. As I had a whole lot of work experience my teaching activities were not a problem, but from an overall point of view I was advised to pursue an Master degree. As my highest educational level up to now is a Bachelor I first had to follow a pre-master program before I could start the Master program. I will write about my experiences of the pre-master program later.

Software Quality Management {#software-quality-management}

I just finished the Software Quality Management course. It was a fun course that focused on the maintainability of code and measuring objective quality metrics. As is usual in a Master you read a lot of papers on the topic, from McCabe's complexity measure to Fuggetta et al. on the evolution of the software development process. All these papers were very interesting and have given me insights into the evolution of software development. It was enlightening to offset those papers with my own experience.

Most of the papers are from the late 1990's up to the early 2010's. During that time I worked in Silicon Valley and within the Dutch startup environment. All these companies were on the frontline of new technologies and methodologies. The papers hit home most of the time. Several papers on the implementation of Scrum and how software evolves felt a bit one-sided from an academic point of view, but that did not bother me too much.

The Rascal Programming Language {#the-rascal-programming-language}

One of the more interesting parts of the course was to write our own metric collection and visualization in the Rascal Meta Programming Language. Rascal is a domain specific language that allows you to reason about source code by building models and then querying these models.

In my group we implemented metrics collection for unit size, complexity, duplication and code coverage (testing). These were very interesting problems to attack and the result was a very cool visualization using D3js.

The project hit a happy place for me. As a result I going to work on an extension for Rascal for my Master Thesis.

References {#references}

Some of the articles that were used in the course are listed below.

  • McCabe (1976) A Complexity Measure, IEEE Transactions on Software Engineering.
  • Fuggetta, Di Nitto (2014) Software Process, ACM.
  • Bennett, Rajlich (2000) Software Maintenance and Evolution: A Roadmap, Association for Computing Machinery.

#education

Original Post {#original-post}

During each in-person Hack The Box meetup I have a small badge challenge that will give the first solver of the challenge a price. at the meetup of March 2023 there will be a very nice little challenge to be done as well, a beautiful NOVI hoodie. You can already download the password protected zip archive. The password will be shared during the meetup opening words.

Good luck. Afterwards I will post a walkthrough of the challenge on this site. Badge Life is hard :)

Walkthrough {#walkthrough}

As usual, the solving of this challenge did not go as expected.

When you first receive the challenge a quick binary analysis will show you that there is a condition of the passphrase. It has to 24 characters in length and the ascii value has to sum up to 2137. During the meetup there were some hints as to how to find the passphrase, namely that I said that I posted in LinkedIn about the challenge and Salp had a “credmp talks too much” on his badge. Sadly the hints were not picked up and people started writing bruteforcers for gigantic dictionaries. Eventually I updated my initial blog post to have all the information that was necessary so that the challenge could be solved.

A wise lesson here is to not rely on multiple sources for the challenge, and if so, make it much more direct. What should've been a fun, quick, bruteforcers ended up in a days long torment.

The original LinkedIn message on the badge challenge had all the information that was required. Lets check it out in the following figure.

{{< figure src=“/ox-hugo/linkedin-badge-challenge.png” alt=“The linkedin post” width=“100%” >}}

By creating a bruteforcer, as MrHaas did for the blog post, a script as the following could be created.

from itertools import combinations, permutations
from tqdm import tqdm
import pwn

pwn.context.log_level = "error"

post = """
    Badge Challenge 3
March 12, 2023 · 1 min · Arjen Wiersma
During each in-person Hack The Box meetup I have a small badge challenge that will give the first solver of the challenge a price. at the meetup of March 2023 there will be a very nice little challenge to be done as well, a beautiful NOVI hoodie. You can already download the password protected zip archive. The password will be shared during the meetup opening words.
    The zip archive (sha1: 28e84243c79caefce06f62ba2c5d930de37a3439)
Good luck. Afterwards I will post a walkthrough of the challenge on this site.
"""


def ssum(s):
    return sum(ord(c) for c in s)


def iter_passphrases(words, n):
    for comb in combinations(words, n):
        if sum(len(word) for word in comb) != (24 - n + 1):
            continue
        if sum(ssum(word) for word in comb) != (2137 - (n - 1) * 32):
            continue

        for perm in permutations(comb):
            yield " ".join(perm)


if __name__ == "__main__":
    word_list = open("./dutch_common_wordlist.txt").read().split()
    words = [word.strip(".?!()#") for word in post.split()]
    overlap = set(word_list) & set(words) | {"Life"}

    for n in range(3, 6):
        print(f"Trying {n} words")
        for passphrase in tqdm(iter_passphrases(overlap, n)):
            with pwn.process(["./badge3", passphrase]) as ps:
                result = ps.recvall()

                if b"Sorry" not in result:
                    print(passphrase)
                    print(result.decode())
                    break

More interestingly, chatgpt can be leveraged to create a brute forcing program, however it is not very good. ChatGPT gets confused on how to use the itertools package to generate the combinations. However, it is a good starting template.

{{< figure src=“/ox-hugo/badge3-chatgpt.png” alt=“Getting help from ChatGPT” width=“100%” >}}

Finally, here is the actual Rust code for the challenge.

use std::env;
use std::str;

fn main() {
    let mut args: Vec<String> = env::args().collect();

    println!(
"
Badge Life (in ASCII art)
");

    if args.len() == 1 {
        println!("Usage: {} passphrase", args[0]);
        return;
    }

    args.remove(0);
    let pass = args.join(" ");

    let mut sum = 0;
    for p in pass.chars() {
        sum = sum + (p as i32);
    }

    if pass.len() != 24 && sum != 2137 {
        println!(
            "That is not a correct passphrase (len {} sum {}), try again!",
            pass.len(),
            sum
        );
        return;
    }

    println!("That might work.... lets try it!");

    let password = pass.as_bytes();

    let encrypted = [
        166, 245, 144, 245, 161, 25, 252, 210, 105, 138, 33, 57, 160, 128, 18, 25, 38, 0, 0, 0, 0,
        0, 0, 0, 6, 171, 134, 183, 188, 103, 63, 69, 199, 190, 26, 116, 174, 217, 135, 232, 211,
        26, 102, 245, 226, 186, 82, 70, 104, 59, 170, 231, 162, 92, 120, 130, 135, 108, 134, 108,
        22, 81,
    ];

    let plain = simplestcrypt::deserialize_and_decrypt(&password[..], &encrypted);

    match plain {
        Ok(v) => {
            let conv = str::from_utf8(&v);
            match conv {
                Ok(key) => println!("Here is the key: {:?}", key),
                Err(_) => println!("Sorry, it was not the right phrase"),
            }
        }
        Err(_) => {
            println!("Sorry, it was not the right phrase");
            return;
        }
    }
}

The passphrase was: Badge Life at The meetup