-Поиск по дневнику

Поиск сообщений в rss_thedaily_wtf

 -Подписка по e-mail

 

 -Постоянные читатели

 -Статистика

Статистика LiveInternet.ru: показано количество хитов и посетителей
Создан: 06.04.2008
Записей:
Комментариев:
Написано: 0

The Daily WTF





Curious Perversions in Information Technology


Добавить любой RSS - источник (включая журнал LiveJournal) в свою ленту друзей вы можете на странице синдикации.

Исходная информация - http://thedailywtf.com/.
Данный дневник сформирован из открытого RSS-источника по адресу http://syndication.thedailywtf.com/thedailywtf, и дополняется в соответствии с дополнением данного источника. Он может не соответствовать содержимому оригинальной страницы. Трансляция создана автоматически по запросу читателей этой RSS ленты.
По всем вопросам о работе данного сервиса обращаться со страницы контактной информации.

[Обновить трансляцию]

CodeSOD: Extended and Empty

Четверг, 17 Марта 2022 г. 09:30 + в цитатник

We've discussed extension methods in .NET in the past. If you write a method with a signature like public static void foo(this string input), then you can invoke this method like myString.foo(). It acts like an instance method to a caller, but it really just invokes foo(myString). It's a nice way to inject functionality into existing classes, and many .NET libraries use this feature.

Esromhaz's co-worker found an… application of this.

public static bool IsNullOrEmpty(this string str) { return string.IsNullOrEmpty(str); } public static bool IsNotNullOrEmpty(this string str) { return !string.IsNullOrEmpty(str); }

Now, the default IsNullOrEmpty is a static method, because it has to be- if myString is null, I can't call IsNullOrEmpty on it. That doesn't make sense. But the co-worker clearly disagreed with this limitation and wanted it to look like an instance method.

So, this actually does work:

string myString = null; bool isNull = myString.IsNullOrEmpty();

Which is… an interesting behavior. This code is old enough that it might predate .NET's addition of nullable types, which it ends up sort of imitating, though I think that's more of an accident.

This makes the code weirder, and certainly would confuse someone not used to the codebase. I'm sure the original developer thought it was mighty convenient though.

[Advertisement] Continuously monitor your servers for configuration changes, and report when there's configuration drift. Get started with Otter today!

https://thedailywtf.com/articles/extended-and-empty


Метки:  

CodeSOD: Rename This

Среда, 16 Марта 2022 г. 09:30 + в цитатник

Visual Basic .NET is actually not a terrible language. I don't think it'd ever be anyone's favorite language, and these days it's basically deceased, but it's essentially C# with verbose syntax. Even the APIs are identical…

… almost.

Because, you see, when Microsoft released VB .NET, their core plan was that it should be "easy" to port your existing VB6 code into VB .NET. This meant recreating a lot of static functions in the global namespace, like Mid (substring), or Kill (file delete). There were better, cleaner ways to do all of those things. For example, Kill throws an exception if you try and delete a file that doesn't exist, while File.Delete doesn't (but provides a status code).

So while you should use the newer APIs, you could still do things the old fashioned way. It was like GoTo- you shouldn't use it, but you could.

Russell F inherited some code which has all of these fun tricks.

Private Sub Rename_OutputFile() Dim strWrkName As String Dim Counter1 As Integer 'Bob Flemp 'Set output file variable... strWrkName = Mid(strInput, 1, InStr(1, strInput, ".")) & "tmp" strOutput = Mid(strInput, 1, InStr(1, strInput, ".")) & "out" ' If Dir$(strOutput) = "" Then GoTo RenameOutput1 'tempremove Bob Flemp 'Delete Existing output file... Try Kill(strOutput) Catch End Try Counter1 = 0 RenameOutput1: 'Rename temp file to output file... Try Rename(strWrkName, strOutput) Catch ex As Exception Counter1 = Counter1 + 1 If Counter1 > 10 Then If ActionCode.ToLower <> "t" AndAlso Not File.Exists(strWrkName) Then Exit Sub 'Bob Flemp - 112613 MsgBox("Cannot rename temporary output file from" & strWrkName & " to " & strOutput & "." & ControlChars.CrLf & "Reason is: " & ex.ToString) Else System.Threading.Thread.Sleep(100) GoTo RenameOutput1 End If End Try Log("leaving Rename_OutputFile") End Sub

"Bob Flemp" helpfully commented the lines he changed. Sometimes with just his name, sometimes with the date. The team was using source control, so none of that was necessary.

The pattern here is that they first do some string munging to get the paths arranged correctly. Then they try and delete the file at the destination, if it exists, catching any exceptions in that process. It's worth noting that there are many possible errors arising from deleting a file, not just that it didn't exist, but we just ignore them all. Plus, as deployed, the file being deleted should almost never exist, so almost all of the exceptions being thrown would be real exceptions that we need to handle properly.

Note also the commented out Dir$ call, which enumerates all the files matching the input pattern- this is a vestigal check to see if the output file exists before deleting it. This was probably a better choice than the catch-all exception block, which adds the frustration of seeing that they had a better thought at one point, but changed their minds. Then again, it also uses GoTo for control flow, so let's not credit them too much.

We get our block to actually do the renaming, complete with a retry counter and a loop implemented in GoTos. If, after ten attempts, we fail to rename, we either exist the subroutine without any hint of what just happened, or we pop up a message box explaining the error. I'm sure this never confuses any users.

It's worth noting that retrying the move every tenth of a second for one whole second is probably not going to resolve whatever locking issue prevented the rename in the first place. In the end, it's just a nice convenient way to waste some time before popping up an error- but time that other parts of the program might be depending on.

Russell writes:

I was allowed to refactor it, but I was too afraid to really change the basic structure (this code is such a mess that it may break a lot of other stuff) so my refactored version isn't really much better.

Private Sub RenameOutputFile() Dim basePath As String = BaseAuth() Dim srcPath As String = basePath & "tmp" Dim destPath As String = basePath & "out" For i As Integer = 1 To 10 Try File.Delete(destPath) File.Move(srcPath, destPath) Return Catch If i = 10 Then Throw Else Threading.Thread.Sleep(100) End If End Try Next End Sub

It's easier to read, at least, but the basic stupidity is still there.

[Advertisement] Otter - Provision your servers automatically without ever needing to log-in to a command prompt. Get started today!

https://thedailywtf.com/articles/rename-this


Метки:  

Court-Martial

Вторник, 15 Марта 2022 г. 09:30 + в цитатник

REF 4

At the age of 17, our friend Argle had a job as a programmer for an aerospace firm, mostly working with commercial flight-deck equipment. Like with anyone new to a given industry, he found himself puzzling over the plethora of acronyms that got thrown around in conversation without a thought. Lacking an Internet to go look these things up in, Argle was forced to ask people to stop, go back, and explain. But what 17 year-old feels comfortable interrupting much older adults like that? Most of the time, the acronyms were scribbled down on a yellow legal pad, to be figured out later.

The programming side of the job was no problem, at least. There was one case of something a little odd: someone handed him some coefficients of a polynomial and told him to make them into a FORTRAN function. He had no familiarity with curve fitting, but that part of the work had already been done for him. He implemented the function and moved on to other things.

Some weeks later, he was working at his cube when a stern voice behind him caught his attention. "Mr. Argle."

It was that tone of voice specifically reserved for calling someone to the carpet, and it made his viscera plummet. Swiveling around in his chair, he beheld a dozen people or more crammed all along the perimeter of his cube and spilling into its cramped confines. Some were in fancy business suits, some in full military regalia. All were wearing the most furious expressions he'd ever seen.

Argle must've started an inch out of his chair.

"Mr. Argle." The military man closest to him spoke again, this time with the full weight of his glare bearing down on him. "We have jets that won't fly because of you."

"Me?" Argle sputtered. "But—"

"That FORTRAN polynomial function we assigned to you!" another voice piped up. "That has to be it! You either made a mistake because you were careless, incompetent, or for some worse reason."

"That?!" Argle's brain raced faster than it had ever raced before. "No! Here!" He swiveled to face his desk and sifted through a pile of folders sitting there. He'd been good about documenting all his work thus far, detailing the whats, whys, and hows. It took him a minute, as his hands shook and his panicked brain had trouble processing the words he looked at, but he was able to find his notes, along with the original coefficients that had been handed to him. He all but heaved the assembled evidence toward his prosecutors. "Here! This is all I did, I swear!"

The tight crowd of higher-ups crowded even tighter around the papers, muttering inaudibly to one another and occasionally coughing. Their collective wrath dissipated, leaving behind an awkward gap of silence. At last, someone said a simple "Thanks" and handed the papers back to Argle. They marched off together, presumably to do this all over again to another poor soul who lacked adequate shielding.

Argle heaved a sigh of relief. That day, he learned that the most important business-related acronym is and always shall be CYA.

[Advertisement] Otter - Provision your servers automatically without ever needing to log-in to a command prompt. Get started today!

https://thedailywtf.com/articles/court-martial


Метки:  

CodeSOD: When You Can't Use WordPress

Понедельник, 14 Марта 2022 г. 09:30 + в цитатник

Initech had a lovely little Content Management System built by a third party that was good at "building" CMSes. That is to say, this company knew its way around a WordPress template.

When Initech needed a new public-facing website, they went straight back to that vendor. Now, this new website was a complicated statistical tool, with all sorts of complicated business rules and requiring a large amount of custom programming. So the vendor that just cranked out WordPress templates may not have been a good fit for the project, but that didn't stop anybody.

That's how Magnus M found code which looks like this:

$dataTotalArray[$md['adt_group_id']][$md['atss_id']]['adt_text'] = $md['adt_text']; if($md['type'] == "totalthisyear") { $dataTotalArray[$md['adt_group_id']][$md['atss_id']]['amount'] = $md['amount']; $dataTotalArray[$md['adt_group_id']][$md['atss_id']]['count'] = $md['count']; }

There are so many nested braces here I'd almost suspect this was a LISP dialect instead of PHP.

That's just ugly and incomprehensible, and it isn't the WTF. The real WTF is that someone had it in their head that "web code" meant anyone doing "view source" could see the code. This complete misunderstanding about what constitutes server-side code lead them to ensure that all their constants were obfuscated via an MD5 hash.

if($_GET['size_cat'] == '59e9effecfe048c8-b13a76da69cc12df') { $adt_old_type = 0; } else { $adt_old_type = 1; } // later in document - in the "presentation" part if ($_GET['size_cat'] == '59e9effecfe048c8-b13a76da69cc12df') { echo "ADT"; } else { echo "ADT"; }

Magnus writes:

In some cases even the arguments to their stored procedures requires the arguments MD5'ed. Makes for wonderful debugging.

[Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!

https://thedailywtf.com/articles/when-you-can-t-use-wordpress


Метки:  

Error'd: Past Time

Пятница, 11 Марта 2022 г. 09:30 + в цитатник

This week we're throwing a bone to all the antipunsters in the audience and declaring a unilateral cease-fire on all alliteration, wordplay, jabs, jokes, or other japery. Starting now.

Allie shares a redundancy that I think we've seen here before, saying "It may be _technically_ right, but I don't have to like it."

vertical

 

Dane Christian sarcastically intones "Nice error message and if that's really the full stack trace I'm happy I'm not supporting this site."

logout

 

Regular contributor Peter G. figures the math doesn't add up [I tried, honest!], reporting "It looks like Covid-19 has jumped to sheep in New Zealand since there's only about 5 million people there but apparently 17 million cases." Seems like we've seen an another Error'd much like this one out of NZ quite recently. I wonder if it's something in the water.

covid

 

Max chimes in with an observation on irony. "You'd think NIST would keep better track of time and dates."

time

 

Finally, another repeat contributor Marek (aka NeverConfusedForNaught) shares a very odd graph. "My battery was failing me - that I already knew. I thought I anticipated all failure modes of a dying battery, but this one they taught me impossible!"

bateria

 

[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!

https://thedailywtf.com/articles/past-time


Метки:  

CodeSOD: Constantly Sinister

Четверг, 10 Марта 2022 г. 09:30 + в цитатник

Cat has some Java code which handles text layout. Now, someone writing the code didn't understand the idea of enumerated types, so every constant is a string.

That's a nuisance, but not a terrible problem. Of course, with Java's String handling, you also run into the fact that == will frequently work, because Java tries to reuse String instances, but it won't always work, and thus equals exists.

So this code didn't actually work:

if (alignment == LEFT_ALIGN) { return RIGHT_ALIGN; } else if (alignment == RIGHT_ALIGN) { return LEFT_ALIGN; } else { return CENTER_ALIGN; }

But even if it did, the only thing I can think when I look at this code is: "No, your other left!"

[Advertisement] Otter - Provision your servers automatically without ever needing to log-in to a command prompt. Get started today!

https://thedailywtf.com/articles/constantly-sinister


Метки:  

CodeSOD: Wear a Wrap

Среда, 09 Марта 2022 г. 09:30 + в цитатник

While jQuery isn't as popular today as it once was, its still a widely used "utility belt" library. Its popularity arises from the fact that it takes cumbersome APIs and wraps convenience functions around them.

But what if those convenience functions are too convenient, like Ryan's co-worker found. For example, if you want to perform an asynchronous HTTP request using jQuery, you could do something like:

$.ajax({ url: urltosend, type: posttype, data: datatosend, dataType: datatype, context:cntxt, success: successfunction, error: errorfunction });

Now, we can object to passing callbacks directly instead of using promises here, but we have a complex call with a lot of parameters and so we wrap those parameters in an object to ensure they're clearly named and readable. It allows the flexibility of constructing the request in multiple steps before actually sending it.

But what if you don't want any of that, and like counting parameters to make sure you've properly passed your inputs?

function callAjax(urltosend,posttype,datatosend,datatype,cntxt,successfunction,errorfunction){ $.ajax({ url: urltosend, type: posttype, data: datatosend, dataType: datatype, context:cntxt, success: successfunction, error: errorfunction }); }

Now that's convenient.

[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.

https://thedailywtf.com/articles/wear-a-wrap


Метки:  

CodeSOD: Hey, Backoff!

Вторник, 08 Марта 2022 г. 09:30 + в цитатник

The Strategy Pattern, like any other design pattern, is supposed to help us write code that's flexible and easy to modify. In the case of the strategy pattern, you have one class, the Context, which has a member which implements a Strategy interface. The actual implementation lives in the Strategy, but the Context is the object that other code in the program consumes. Ideally, this means that you can change the behavior of your Context by simply swapping a different Strategy implementation in.

On the flip side, when it gets out of hand, you might end up like Dotan, consuming an API from a major cloud vendor, written with a terminal case of "Pattern Brain".

$backoff = $config->get(Options::BACKOFF); if ($backoff === null) { $backoff = new BackoffPlugin( // Retry failed requests up to 3 times if it is determined that the request can be retried new TruncatedBackoffStrategy(3, // Retry failed requests with 400-level responses due to throttling new ThrottlingErrorChecker($this->exceptionParser, // Retry failed requests with 500-level responses new HttpBackoffStrategy(array(500, 503, 509), // Retry failed requests due to transient network or cURL problems new CurlBackoffStrategy(null, // Retry requests that failed due to expired credentials new ExpiredCredentialsChecker($this->exceptionParser, new ExponentialBackoffStrategy() ) ) ) ) ) ); }

This was from the official vendor documentation, representing a pretty standard request that would run on every single page load.

Now, I'm sure this code works, and I'm sure that this chain of tested strategies and error handlers has a very good purpose. And maybe my hatred of deep nesting is just an aesthetic objection, and this isn't really a WTF.

But this is the worst way I can imagine to do this, even if you're insistent on chaining together all these objects. It's hard to read, and difficult to understand the purpose of all these, even the order of them- does it matter?

This is an API that's so flexible that it forgot to make the common use cases accessible to most developers. And while it'd be easy to wrap this up in some convenience methods, if it's a major vendor, one would hope that the API is a little more finished- even if it is the PHP implementation.

[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!

https://thedailywtf.com/articles/hey-backoff


Метки:  

CodeSOD: Administrative Transfer

Понедельник, 07 Марта 2022 г. 09:30 + в цитатник

When the pandemic started, a lot of companies needed to cut back, and Initech was no exception. In the Before Times™, Initech had an offshore development team that maintained an application inherited from an acquisition. Now that everyone was tightening their belts, though, that had to go. The offshore team was released and the application they supported ended up in the hands of Lovelace.

Lovelace dug in, and they quickly discovered a few things. From 2010-2017, the application's idea of source control was a folder on an FTP server and a lot of files named some_module.php.old and some_module.php.donotuse. In 2017, someone put the project into Git, but the commits were just point-in-time snapshots of the FTP folder. Deployment? Just work right on that FTP folder, it's fine. And if you forget to commit those changes back to source control? No biggie- consider the FTP folder the source of truth.

Then again, when Lovelace saw the "truth" that was there, they weren't exactly excited to be supporting this PHP application.

if (!isset($_SESSION['ADMIN_ID']) or empty($_SESSION['ADMIN_ID']) or $_SESSION['ADMIN_ID'] == NULL) { $isAdmin = false; } else { $isAdmin = true; }

Now, this isn't going to be anybody's favorite code, but it's not a WTF. If the session variable ADMIN_ID doesn't have a meaningful value, then we're not in admin mode, otherwise we are. It's ugly, and I think redundant: while isset and empty are actually different, isset includes a NULL check.

As Lovelace writes:

While ugly, this really isn't so bad. It's not like you can set session variables from the client.

Of course you can't. Right? Right?

if (isset($_COOKIE["SESSION"])) { foreach ($_COOKIE['SESSION'] as $name => $value) { $_SESSION[$name]= $value; } }

This block is copy-pasted into the top of every page, because what's an "include file"? This looks for all the sub-cookies under SESSION and just loads them directly into $_SESSION. So a cookie named SESSION[ADMIN_ID] would get stored in $_SESSION['ADMIN_ID'].

So now, anyone who could open up the dev tools could easily make themselves an admin. And there were many admin pages, and as you can imagine, the admin validation was also copy-pasted into every admin page, right under the cookie/session loader. And an exploiter wouldn't need to guess the correct value- any non-false, non-null value is going to grant them admin access.

Or set/alter any session variable. Who knows what else might be in there?

Lovelace raised this up to their management. "Oh, it's no big deal," management said, "because we're going to stop selling this software sometime really soon. I mean, we did just sign a three year contract with a large customer, but like, really soon, nobody will be using this anymore."

[Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.

https://thedailywtf.com/articles/administrative-transfer


Метки:  

Error'd: The Hardest Problem

Пятница, 04 Марта 2022 г. 09:30 + в цитатник

It has been infamously stated that the two hardest problems in computer science are naming, caching, and off-by-one errors. Mixing and matching arrays indexed from 0 with arrays indexed from 1 could be a special-case of the off-by-one error.

The zeroth of a sudden rash of anonymous posters spotted this initial example, coughing "Pre-increment seems somehow inappropriate here."

one

 

Carlos follows up with a third, muttering "The image is pretty self-explanatory. Off-by-one error, maybe? I don't even know." Honestly, it took me a moment.

amazon

 

Another topically anonymous donor wonders "Are those $USD or $AUD?" Must be US dollars; in OZ they'd be $aNa.

gitea

 

The last of our anonymous cohort crowed "Vaccination rate is better than I thought."

coverage

 

Finally, the not entirely anonymous David B. dishes on his disguised employer. "At $WORK to log into some of the external sites requires SSO, sometimes SSO gives you a nice error message. Sometimes you get this. $WORK is a very large software company, it should be able to do better."

ajax

 

[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.

https://thedailywtf.com/articles/the-hardest-problem


Метки:  

CodeSOD: A Cup of CIDR

Четверг, 03 Марта 2022 г. 09:30 + в цитатник

Marco sends us some code that he wrote, back in the far off days of 2003. He wrote some code to handle network addresses. Unfortunately, it never quite worked. Specifically it could only handle addresses in the /24 subnet.

Now, this was written in Perl, so you know it involves regexes.

@IPstart = split(/\./,$start); @IPend = split(/\./,$end); &Check_Start_and_EndIP; # converts "short" (dotted) IPs to "long" (undotted) IPs $IPstart = (($IPstart[0]*16777216)+($IPstart[1]*65536)+($IPstart[2]*256)+$IPstart[3]); $IPend = (($IPend[0]*16777216)+($IPend[1]*65536)+($IPend[2]*256)+$IPend[3]); if($IPend < $IPstart) { die "Can't scan backwards"; } $CountIp = $IPstart; $EndIp = $IPend+1; while($CountIp ne $EndIp) { @Class = &GetIP($CountIp); push(@targetlist, "$Class[1]\.$Class[2]\.$Class[3]\.$Class[4]"); $CountIp++; }

This, by the way, is Marco's attempt to fix the broken code. As Marco puts it: "I am not a coder. I 'fix' things."

[Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!

https://thedailywtf.com/articles/a-cup-of-cidr


Метки:  

CodeSOD: A Forgotten Memory

Среда, 02 Марта 2022 г. 09:30 + в цитатник

Starting in 1985, a tiny little language called Clipper briefly conquered the world. It was a dBase-derivative, with the bonus that its programs could be compiled and run as stand-alone software on MS-DOS. That meant small programs which couldn't justify getting time on a mainframe or a minicomputer could be whipped up to run on a desktop. It was popular, and for about a decade, it was everywhere. Then Windows 95 came out, and Clipper refused to pivot to Windows and became a footnote in history.

It mostly worked pretty great, or at least as great as one of those tiny business-focused languages ever got. Unfortunately for Drake, he encountered some issues in the latter days of Clipper in the early 90s.

Drake's team wrote an image display library for Clipper programs. An end-user of their library complained that it crashed when displaying images. They supplied a sample program that replicated the issue, and Drake and his colleagues were able to repeat the issue.

The core pattern was: allocate memory for an image, display the image, release the memory. Repeat that a few times, and eventually it crashed. There were a few other memory allocations along the way, and they all went through Clipper's memory manager.

So Drake and his team started stripping back their code, commenting out operations until they had a bare minimum program which could replicate the crash. By the time they were finished, the only code left was the code which allocated memory and released it. The simple test case program simply performed a series of memory allocations and releases, and repeated that, printing out the iteration number.

On some machines, the program crashed after 22 iterations. On others, it crashed after 151. It was consistent, always crashing on the same iteration on the same machine. Machines with otherwise identical hardware could end up being in either the 22 or the 151 group. A consistent program to reproduce the bug meant that Drake had something to send Nantucket, the company making Clipper.

Drake explains what happens next:

The interesting part was some of the feedback we got. Our customer service contact told us that our test program had kind of blown up on their internal message board. We were told that some of the developers were complaining that our program was silly, because it didn't do anything with the memory we were allocating.

Doing anything or not, the program triggered its crash consistently. Tempers were flaring on the Nantucket side, and after some increasingly heated back and forth, the customer service contact gently ended the conversation: "We'll get back to you in a few days."

A few days later, there was a solution: the current memory manager in Clipper would be deprecated, and Drake's software should just start using the new one that would become the standard in a future release. This did fix the crash, and so that's what Drake's team did.

We never did get an explanation of why simple memory allocations were hosing their memory manager, nor if they ever fixed it.

Well, arguably, they did fix it, simply by completely replacing their approach to memory management. The actual source of the bug may be lost to time, though I'd love to find out what really happened on the other side of that customer service rep.

For now, though, it needs to remain an interesting historical mystery…

[Advertisement] Otter - Provision your servers automatically without ever needing to log-in to a command prompt. Get started today!

https://thedailywtf.com/articles/a-forgotten-memory


Метки:  

CodeSOD: It's Not None of Your Business is True

Вторник, 01 Марта 2022 г. 09:30 + в цитатник

Patricia's employer hired her because she knew Python. They were a Python shop, at least at this point, but they'd never actually hired a developer with Python experience before.

At some point, their PHP developer wanted to branch out, and decided to solve a problem using a small Python script. It was very successful, and features got added to it. In a surprisingly short amount of time, the script expanded until it was two separate web applications which were absolutely critical to business operations.

It was a bit of a mess, when Patricia took over. The code was split across three source control repositories. One was for "Application A", in its entirety. One was called "Application B Backend", which as the name implied was the backend of Application B. The third was called "Application B" and was described as the "front end" but it was actually a copy of "Application B Backend".

It was 40,000 lines of copy-pasted nonsense, and the core of it was a module called "gsf" or "general standard functions". It was almost all of the shared logic across modules. It was designed so that it never raised an exception, and instead every method that could possibly have to deal with an exception condition instead returned a tuple: (actualReturnValue,successBoolean). Thus, you could invoke something like this:

entity, succesful = gsf.getCustomerByPrimaryKey(primary_key) if successful: …

Now, that'd be annoying but tolerable. Definitely not a WTF. But that's not how this code got used. Instead of that, the developer wrote it like this:

entity, succesful = gsf.getCustomeryByPrimaryKey(primary_key) if not (entity is None) == True: # hundreds of lines of code... else: gsf.saveLogInDatabase("Something went wrong") return

You see, if the operation failed, successful would be false, but the entity returned would also be None.

Now, the Pythonic way to write that would be to say: if entity:- None is always "false-y". Instead, the developer responsible found the most convoluted way to express the idea, ignoring the perfectly good boolean value they could have used in the first place, ignoring the behavior of None values, and instead just… spamming operations.

The preferred way would be to throw exceptions. The second best would be to if successful, then if entity, then if entity is not None, then if not (entity is None), and if you'd just consumed a vat of rubbing alcohol and held your breath for five minutes, finally your choice would be if not (entity is None) == True.

So yes, I hate that, but let's not ignore the absolute glory that is the else error handler. I'll let Patricia summarize:

The error message "Something went wrong"t was not printed to a logger or to stdout or to a file, but to a database table that contained about two million rows of the sentence "Something went wrong"

I'm just surprised that it was only two million, and I assume someone truncated the table.

Oh, there is another surprise here. Again, I'll let Patricia explain:

Luckily for me, the software manager understood my plight and let me rewrite everything from scratch.

[Advertisement] Continuously monitor your servers for configuration changes, and report when there's configuration drift. Get started with Otter today!

https://thedailywtf.com/articles/it-s-not-none-of-your-business-is-true


Метки:  

CodeSOD: Switch Kicker

Понедельник, 28 Февраля 2022 г. 09:30 + в цитатник

As covered previously, game code generally doesn't represent an interesting WTF. But bad e-commerce code certainly does. So today, Rhys sends us some JavaScript from a web-based fantasy-football (for non-USA values of football) site. Given that it handles microtransactions and in-game items passed between players, it's definitely more on the e-commerce side of things than anything else.

And much like that previous article, this one does involve a very large switch, but before we get to the switch, we have to get to the state validator:

else if(propertyName == "initUser" || propertyName == "updateUser" || propertyName == "submitLogin" || propertyName == "initRequestPasswordForm" || propertyName == "submitPasswordRequest" || propertyName == "resetPassowrd" || propertyName == "submitGameLogin" || propertyName == "deleteAlertReturn" || propertyName == "submitRegistration" || propertyName == "submitGameRegistration" || propertyName == "acceptGiftReturn" || propertyName == "sellGiftReturn" || propertyName == "buildTicker" || propertyName == "submitAward" || propertyName == "submitGameAward" || propertyName == "buyAsset" || propertyName == "sellAsset" || propertyName == "giftAsset" || propertyName == "loadArcadeProgress" || propertyName == "getGameCompositeAward" || propertyName == "visitFriend" || propertyName == "createGuestUser" || propertyName == "isOnBoard" || propertyName == "processCompletedCompetition" || propertyName == "handleNewPasswordSent" || propertyName == "resetPassword" || propertyName == "submitFriendMail" || propertyName == "savePitchPosition" || propertyName == "cardGiftConfirmed-noOverlay" || propertyName == "startCompetitionAfterCRNUpload" || propertyName == "handleReferralThanks" || propertyName == "loadPriamStore" || propertyName == "buyPriamItem") { handlePostRender(propertyName, data); }

Now, they're validating inputs, which is good, but the pile of magic strings begs for being turned into constants (and thus helping avoid input errors in the first place), or some sort of array check or something to make this more readable.

But inside the handlePostRender we process these inputs, which also highlights how not necessary this if statement even is:

case "openStore": if(tutorial.hasStarted) if(tutorial.current == 5) { ajaxEngine.googleTrackEvent("event", {category:"pre-registration", action:"enter-store", label:"set-up-process"}); tutorial.next(); // hide close button $(".close-button").css("display", "none"); // append tutorial to overlay $('#tutorial').clone().appendTo('#Award-shopfront-overlay'); $("#Award-shopfront-overlay").find("#tutorial-6").show(); } setupStoreButtons(); break; case "loadFriends": populateFriendList(assetsObject); break; case "loadFriendsAfterAdd": populateFriendList(assetsObject, true); break; case "addFriend": populateFriendList(assetsObject); break; case "joinInvitation": handleJoinInvitation(assetsObject); break; case "loadStore": populateStore(assetsObject); break; case "initUser": setupAwardDetails(assetsObject); break; case "updateUser": updateAwardDetails(assetsObject); break; case "loadGiftChoose-appendOverlay-opaqueBack": populateGiftFriendList(assetsObject); break; case "loadCardGiftChoose-appendOverlay-opaqueBack": populateCardGiftFriendList(assetsObject); break; case "customiseAward": populateAward(assetsObject); break; case "customiseGameAward-noOverlay": populateGameAward(assetsObject); break; case "giftConfirmed-noOverlay": showGiftSent(assetsObject); break; case "cardGiftConfirmed-noOverlay": showCardGiftSent(assetsObject); break; case "processMessage": displayMail(assetsObject,-1); break; case "login": initLogin(); break; case "submitLogin": //loaderfeedback.hide(); handleSubmitLogin(assetsObject); break; case "submitPasswordRequest": handleSubmitPasswordRequest(assetsObject); break; case "initRequestPasswordForm": initRequestPasswordForm(assetsObject); break; case "resetPassword": account.resetPassword(); break; case "accountDeleted": account.accountDeleted(); break; case "handleNewPasswordSent": handleNewPasswordSent(assetsObject); break; case "submitGameLogin": handleGameLogin(assetsObject); break; case "submitLogout-noOverlay": handleLogout(); break; case "submitLogout-noReload": // do nought, this is handled earlier // in AjaxEngine::makeRequest break; case "deleteAlertReturn": handleDeleteAlertReturn(assetsObject); break; case "register": initRegister(); break; case "submitRegistration": handleSubmitRegister(assetsObject); break; case "submitGameRegistration": handleGameRegister(assetsObject); break; case "acceptGiftReturn": handleAcceptGiftReturn(assetsObject); break; case "sellGiftReturn": handleSellGiftReturn(); break; case "pollReturn": handlePollReturn(); break case "predictionReturn": handlePredictionReturn(); break case "buildTicker": handleTickerTape(assetsObject); break; case "processNews": handleNewsItems(assetsObject); break; case "submitAward": handleAwardSubmitted(assetsObject); break; case "submitGameAward": handleGameAwardSubmitted(assetsObject); break; case "buildPlayerDetails": populatePlayerDetails(assetsObject); break; case "buildPlayerBio": populatePlayerBio(assetsObject); break; case "competitionReturn-noOverlay": handleCompetitionPromoReturn(assetsObject); break case "processCompletedCompetition": handleCompetitionFormReturn() //handleProcessCompletedCompetition(); break; case "processCompetitionForm": handleCompetitionFormReturn(assetsObject); break; case "submitCompetitionCollectedData": handleCompetitionFormReturn(assetsObject); break; case "sellAsset": handleStoreSell(); // When selling item, make sure the turf world // is re-built (and inited, particularly) setupAwardDetails(assetsObject.turf); break; case "buyAsset": handleStoreBuy(); break; case "giftAsset": handleStoreGive(); break; case "handleUnwear": handleUnwear(); break; case "handleWear": handleWear(); break; case "quizReturn-noOverlay": handleQuizPromoReturn(assetsObject); break; case "processQuizForm": handleQuizFormReturn(assetsObject); break; case "printPlayers-noOverlay": handlePrintingPlayerCards(assetsObject); break; case "handlePrintAllTrophiesAndMedals-noOverlay": handlePrintAllTrophiesAndMedals(assetsObject); break; case "handlePrintAllTrophies-noOverlay": handlePrintAllTrophies(assetsObject); break; case "handlePrintAllMedals-noOverlay": handlePrintAllMedals(assetsObject); break; case "printInvite-noOverlay": handlePrintInvite(assetsObject); break; case "loadArcadeProgress": handleArcadeLoaded(assetsObject); break; case "getGameCompositeAward": handleGameCompositeAward(assetsObject); break; case "visitFriend": handleVisitFriend(assetsObject); break; case "createGuestUser": handleCreateGuestUser(assetsObject); break; case "isOnBoard": handleOnBoarding(assetsObject); break; case "submitFriendMail": handleFriendRequestAccepted(assetsObject); break; case "savePitchPosition" : startApp(assetsObject); break; case "handleTrophyOverlay" : handleTrophyOverlay(); break; case "loadMedal" : handleMedalsOverlay(); break; case "setupSaveProfile": account.setupSaveProfile(); break; case "processFinalisedQuiz": processFinalisedQuiz(); break; case "startCompetitionAfterCRNUpload" : processCompetitionCRNThanks(); break; case "handleReferralThanks" : handleSubmitRegisterReferral(assetsObject); break; case "loadPriamStore" : populatePriamStore(assetsObject); break; case "buyPriamItem" : handleBoughtPriamItem(assetsObject); break;

As you might gather here, this repeats all the same validation, but also dispatches to actual actions. Rhys suggests a solution which would likely be close to my own: an object acting as a lookup table with callback functions as the values, e.g.:

let action = { //… "loadPriamStore": () => populatePriamStore(assetsObject), "buyPriamItem": () => handleBoughtPriamItem(assetsObject) } if (propertyName in action) action[propertyName]();

The original code was probably written in an older dialect of JavaScript, but the basic principle is viable, with perhaps some minor modifications to properly enclose the data required by the callbacks, or maybe ways to break the actions into categories and have different lookup tables for different categories of action, so that nothing gets too gigantic. One can nitpick the solutions, but the one that doesn't involve a nearly 300 line switch is probably the right one.

Rhys adds: "I'm able to share this because on the live site, none of the code is minified or obfuscated."

[Advertisement] ProGet’s got you covered with security and access controls on your NuGet feeds. Learn more.

https://thedailywtf.com/articles/switch-kicker


Метки:  

Error'd: Down the Rarebit Hole

Пятница, 25 Февраля 2022 г. 09:30 + в цитатник

This week's Error'd episode includes a bonus submission from our good friend A. Bargle, at no extra charge. TRWTF is in the browser, perhaps, but it's just so gosh darn funny. It's likely that what tickles me is entirely inscrutable to all of you (especially those coming to English as a second language), and if so, I apologize. But at least one of us is having a good time!

Not actually a hydrologist Carl C. has uncovered evidence of an entire cadre of wayward rivers roamin' the wikipedian underground. "I got so excited by this that I forgot why I was looking up the Nueces River on Wikipedia." It's not just the poor lost Rubicon!

malformed

 

Cheesemaster Phil Adelphia striving to engage the TDWTF editors' punsterism, suggests "Microsoft Edge knows the Welsh language when it sees it."

croeso

 

Possibly Welsh Simon T. waffles "I think I'm going to see the film."

schrodinger

 

Probably not Welsh Henry lets his fingers do the talking: "Innovation never ceases at Ticketmaster UK where, instead of stringly typing ints, they prefer to intly type strings."

intly

 

Topical Michael rips a comment straight from the latest headlines: "That whole Russia / Ukraine thing gives that 'undefined country' a completely new meaning."

undefined

 

Alexa acolyte Timothy W. announces "Ah! source of infinite knowledge! I also found out carrots last eight minutes if kept outside the fridge."

alexa

 

And now the promised bonus from reliable Argle Bargle: "Snarky comment? You already took all the fun out of it. :-D" After posting our own page back to us in a deliciously meta riposte, Friend Argle found the fault in his stars and described in last week's comments: "It never dawned on me that my ad blocker would actually analyze an image that I created by screen capture." It never occurred to me, either, buddy Bargle. Here's hoping that the meta-meta post is equally meta-invisible. Comment below!

advert

 

[Advertisement] Continuously monitor your servers for configuration changes, and report when there's configuration drift. Get started with Otter today!

https://thedailywtf.com/articles/down-the-rarebit-hole


Метки:  

Double Bagged

Четверг, 24 Февраля 2022 г. 09:30 + в цитатник

Many years ago, Yazeran needed to work with some floor-plan data. Now, fortunately for Yazeran, a vendor had already collected this information and packed it up behind a SOAP-based web service, so it would in theory be easy to get. This was long enough ago that SOAP was all the rage, and computers with multiple gigabytes of RAM were still on the higher end of things.

In fact, there was an end-point called GetFullDataExtract which promised to, as the name implies, get him all the data. Yazeran didn't need all the data, but the other end-point, GetGMLBuildings returned only the subset of data Yazeran didn't need. So Yazeran simply had to request too much.

Yazeran fired up a wget session with all the appropriate credentials and waited. And waited. And waited…

When the 20MB XML response finally downloaded, minutes later, it looked like this:

<string xmlns="http://tempuri.org/"><DataExtract> <Location ID="13" MasterID="13" Name="Nunich " IsMunicipality="true" ParentMasterID="" DisplayName="Munich "> <Estate ID="31" MasterID="10" LocationID="13" LocationMasterID="13" Name="Munich Campus" Description="" DisplayName="Munich Campus"> <Building ID="6462" MasterID="323" EstateID="31" EstateMasterID="10" Name="Munich" Description="" Address="Kings Road" AlternativeName="" Number="15" City="Munich" ZipCode="6542" BasementGrossArea="17474.495491066667" GrossArea="56913.5818959713" NetArea="47924.600000000079" DisplayName="Munich"> <GIS> <OuterPolygon> <Coordinate x="45.73155848600081" y="11.395289797465072" /> <Coordinate x="45.73133750252103" y="11.396345176530383" /> <Coordinate x="45.73158863712057" y="11.396510410132915" /> </OuterPolygon> </GIS> <Drawing ID="8587" MasterID="1010" BuildingID="6462" BuildingMasterID="198" EstateID="31" EstateMasterID="8" DrawingTypeID="3"> <Floor ID="8640" MasterID="1010" FloorNumber="0" FloorType="1" DrawingID="8587" GrossArea="131.99712099999974" DrawingMasterID="1010"> <Room ID="364742" MasterID="41627" DrawingMasterID="1010" FloorMasterID="1010" NetArea="132" EstimatedGrossArea="132"> <LayerData ID="231389" LayerFieldID="24" Name="ROOM NR." Value="g01" /> <LayerData ID="231390" LayerFieldID="27" Name="TYPE" Value="ROOM" /> <LayerData ID="231391" LayerFieldID="28" Name="CATEGORY" Value="STORRAGE" /> <LayerData ID="231392" LayerFieldID="30" Name="BRUGER" Value="PHYSICS" /> <LayerData ID="231393" LayerFieldID="34" Name="x_UID" Value="B712D571AB564658999E75D65543" /> </Room> </Floor> </Drawing> </Building> </Estate> </Location> <Location ID="14".... </Building> </Estate> </Location> </DataExtract>string>

They produced an XML document with one element, and within that element put an escaped version of another XML document.

XML is large and bureaucratic and complicated, but that complexity comes with benefits- namespaces, schemas, validation, and so on. None of that is possible when you've just mashed your XML into text and then wrapped the text in XML again.

There are other problems with this, beside the obvious. XML parsers are notoriously memory intensive. Your core options are a DOM-based parser, which loads the entire document in memory, and thus is very expensive, or a SAX-based parser, which streams the document and emits events as it encounters nodes in the document. SAX is more difficult to use, but is potentially faster and definitely more memory efficient.

Unless, of course, your XML document just contains one giant text node. In that case, SAX has to load the entire document into memory anyway, and all those efficiency gains vanish. In fact, when Yazeran tried to parse this as-is, it took 40+ minutes and involved a lot of paging.

Now Yazeran was using Perl to do this work, and fixed this with the obvious tool at hand: regexes. No, no parsing XML with regexes, but "un-escaping" the internal text. Since Yazeran was already munging some data, it was easy to add a few more regexes which stripped out the unnecessary data in the document, like the large blocks of Coordinate elements.

That shrunk the document down to a reasonable size that could be parsed using a DOM parser in under 5 minutes.

Yazeran sums it up thus:

It corresponds to writing a letter, putting it in an envelope, adding postage, and then instead of sending the letter, putting it into yet another envelope and adding postage before sending… (in effect paying twice for the same service)

[Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!

https://thedailywtf.com/articles/double-bagged


Метки:  

CodeSOD: Swwwitch

Среда, 23 Февраля 2022 г. 09:30 + в цитатник

We're going to do something a little different. I don't like to do posts about game related code. Games are entirely about shipping something out the door on tight timelines and tight budgets, and it's very much the category of "if it works it's good". There are exceptions, like when you ship an actual WTF, but "bad game code" is not really that interesting.

Awhile back, indie game VVVVVV went open source which gives us a picture of how the sausage is actually made. Now, this is emphatically not a WTF, this isn't wrong or a mistake, this is just the kind of thing that gets a game shipped, especially when it's a small budget indie game, by basically one person.

So instead of getting angry or annoyed, let's just marvel at this 3,440 line switch which represents the game's main loop.

switch(state) { case 0: //Do nothing here! Standard game state break; case 1: //Game initilisation state = 0; break; case 2: //Opening cutscene advancetext = true; hascontrol = false; state = 3; dwgfx.createtextbox("To do: write quick", 50, 80, 164, 164, 255); dwgfx.addline("intro to story!"); //Oh no! what happen to rest of crew etc crash into dimension break; case 4: //End of opening cutscene for now dwgfx.createtextbox(" Press arrow keys or WASD to move ", -1, 195, 174, 174, 174); dwgfx.textboxtimer(60); state = 0; break; case 5: //Demo over advancetext = true; hascontrol = false; /*dwgfx.createtextbox(" Prototype Complete ", 50, 80, 164, 164, 255); dwgfx.addline("Congrats! More Info Soon!"); dwgfx.textboxcenter(); */ startscript = true; newscript="returntohub"; obj.removetrigger(5); state = 6; break; case 7: //End of opening cutscene for now dwgfx.textboxremove(); hascontrol = true; advancetext = false; state = 0; break; case 8: //Enter dialogue obj.removetrigger(8); if (obj.flags[13] == 0) { obj.changeflag(13, 1); dwgfx.createtextbox(" Press ENTER to view map ", -1, 155, 174, 174, 174); dwgfx.addline(" and quicksave"); dwgfx.textboxtimer(60); } state = 0; break; case 9: //Start SWN Minigame Mode B obj.removetrigger(9); swnmode = true; swngame = 6; swndelay = 150; swntimer = 60 * 30; //set the checkpoint in the middle of the screen savepoint = 0; savex = 148; savey = 100; savegc = 0; saverx = roomx; savery = roomy; savedir = 0; state = 0; break; case 10: //Start SWN Minigame Mode A obj.removetrigger(10); swnmode = true; swngame = 4; swndelay = 150; swntimer = 60 * 30; //set the checkpoint in the middle of the screen savepoint = 0; savex = 148; savey = 100; savegc = 0; saverx = roomx; savery = roomy; savedir = 0; state = 0; break; case 11: //Intermission 1 instructional textbox, depends on last saved dwgfx.textboxremovefast(); dwgfx.createtextbox(" When you're NOT standing on ", -1, 3, 174, 174, 174); if (dwgfx.flipmode) { if (lastsaved == 2) { dwgfx.addline(" the ceiling, Vitellary will"); } else if (lastsaved == 3) { dwgfx.addline(" the ceiling, Vermilion will"); } else if (lastsaved == 4) { dwgfx.addline(" the ceiling, Verdigris will"); } else if (lastsaved == 5) { dwgfx.addline(" the ceiling, Victoria will"); } } else { if (lastsaved == 2) { dwgfx.addline(" the floor, Vitellary will"); } else if (lastsaved == 3) { dwgfx.addline(" the floor, Vermilion will"); } else if (lastsaved == 4) { dwgfx.addline(" the floor, Verdigris will"); } else if (lastsaved == 5) { dwgfx.addline(" the floor, Victoria will"); } } dwgfx.addline(" stop and wait for you."); dwgfx.textboxtimer(180); state = 0; break; case 12: //Intermission 1 instructional textbox, depends on last saved obj.removetrigger(12); if (obj.flags[61] == 0) { obj.changeflag(61, 1); dwgfx.textboxremovefast(); dwgfx.createtextbox(" You can't continue to the next ", -1, 8, 174, 174, 174); if (lastsaved == 5) { dwgfx.addline(" room until she is safely across. "); } else { dwgfx.addline(" room until he is safely across. "); } dwgfx.textboxtimer(120); } state = 0; break; case 13: //textbox removal obj.removetrigger(13); dwgfx.textboxremovefast(); state = 0; break; case 14: //Intermission 1 instructional textbox, depends on last saved if (dwgfx.flipmode) { dwgfx.createtextbox(" When you're standing on the ceiling, ", -1, 3, 174, 174, 174); } else { dwgfx.createtextbox(" When you're standing on the floor, ", -1, 3, 174, 174, 174); } if (lastsaved == 2) { dwgfx.addline(" Vitellary will try to walk to you. "); } else if (lastsaved == 3) { dwgfx.addline(" Vermilion will try to walk to you. "); } else if (lastsaved == 4) { dwgfx.addline(" Verdigris will try to walk to you. "); } else if (lastsaved == 5) { dwgfx.addline(" Victoria will try to walk to you. "); } dwgfx.textboxtimer(280); state = 0; break; case 15: //leaving the naughty corner obj.entities[obj.getplayer()].tile = 0; state = 0; break; case 16: //entering the naughty corner if(obj.entities[obj.getplayer()].tile == 0) { obj.entities[obj.getplayer()].tile = 144; music.playef(2, 10); } state = 0; break; case 17: //Arrow key tutorial obj.removetrigger(17); dwgfx.createtextbox(" If you prefer, you can press UP or ", -1, 195, 174, 174, 174); dwgfx.addline(" DOWN instead of ACTION to flip."); dwgfx.textboxtimer(100); state = 0; break; case 20: if (obj.flags[1] == 0) { obj.changeflag(1, 1); state = 0; dwgfx.textboxremove(); } obj.removetrigger(20); break; case 21: if (obj.flags[2] == 0) { obj.changeflag(2, 1); state = 0; dwgfx.textboxremove(); } obj.removetrigger(21); break; case 22: if (obj.flags[3] == 0) { dwgfx.textboxremovefast(); obj.changeflag(3, 1); state = 0; dwgfx.createtextbox(" Press ACTION to flip ", -1, 25, 174, 174, 174); dwgfx.textboxtimer(60); } obj.removetrigger(22); break; case 30: //Generic "run script" if (obj.flags[4] == 0) { obj.changeflag(4, 1); startscript = true; newscript="firststeps"; state = 0; } obj.removetrigger(30); state = 0; break; case 31: //state = 55; statedelay = 50; state = 0; statedelay = 0; if (obj.flags[6] == 0) { obj.changeflag(6, 1); obj.changeflag(5, 1); startscript = true; newscript="communicationstation"; state = 0; statedelay = 0; } obj.removetrigger(31); break; case 32: //Generic "run script" if (obj.flags[7] == 0) { obj.changeflag(7, 1); startscript = true; newscript="teleporterback"; state = 0; } obj.removetrigger(32); state = 0; break; case 33: //Generic "run script" if (obj.flags[9] == 0) { obj.changeflag(9, 1); startscript = true; newscript="rescueblue"; state = 0; } obj.removetrigger(33); state = 0; break; case 34: //Generic "run script" if (obj.flags[10] == 0) { obj.changeflag(10, 1); startscript = true; newscript="rescueyellow"; state = 0; } obj.removetrigger(34); state = 0; break; case 35: //Generic "run script" if (obj.flags[11] == 0) { obj.changeflag(11, 1); startscript = true; newscript="rescuegreen"; state = 0; } obj.removetrigger(35); state = 0; break; case 36: //Generic "run script" if (obj.flags[8] == 0) { obj.changeflag(8, 1); startscript = true; newscript="rescuered"; state = 0; } obj.removetrigger(36); state = 0; break; case 37: //Generic "run script" if (companion == 0) { startscript = true; newscript="int2_yellow"; state = 0; } obj.removetrigger(37); state = 0; break; case 38: //Generic "run script" if (companion == 0) { startscript = true; newscript="int2_red"; state = 0; } obj.removetrigger(38); state = 0; break; case 39: //Generic "run script" if (companion == 0) { startscript = true; newscript="int2_green"; state = 0; } obj.removetrigger(39); state = 0; break; case 40: //Generic "run script" if (companion == 0) { startscript = true; newscript="int2_blue"; state = 0; } obj.removetrigger(40); state = 0; break; case 41: //Generic "run script" if (obj.flags[60] == 0) { obj.changeflag(60, 1); startscript = true; if (lastsaved == 2) { newscript = "int1yellow_2"; } else if (lastsaved == 3) { newscript = "int1red_2"; } else if (lastsaved == 4) { newscript = "int1green_2"; } else if (lastsaved == 5) { newscript = "int1blue_2"; } state = 0; } obj.removetrigger(41); state = 0; break; case 42: //Generic "run script" if (obj.flags[62] == 0) { obj.changeflag(62, 1); startscript = true; if (lastsaved == 2) { newscript = "int1yellow_3"; } else if (lastsaved == 3) { newscript = "int1red_3"; } else if (lastsaved == 4) { newscript = "int1green_3"; } else if (lastsaved == 5) { newscript = "int1blue_3"; } state = 0; } obj.removetrigger(42); state = 0; break; case 43: //Generic "run script" if (obj.flags[63] == 0) { obj.changeflag(63, 1); startscript = true; if (lastsaved == 2) { newscript = "int1yellow_4"; } else if (lastsaved == 3) { newscript = "int1red_4"; } else if (lastsaved == 4) { newscript = "int1green_4"; } else if (lastsaved == 5) { newscript = "int1blue_4"; } state = 0; } obj.removetrigger(43); state = 0; break; case 44: //Generic "run script" if (obj.flags[64] == 0) { obj.changeflag(64, 1); startscript = true; if (lastsaved == 2) { newscript = "int1yellow_5"; } else if (lastsaved == 3) { newscript = "int1red_5"; } else if (lastsaved == 4) { newscript = "int1green_5"; } else if (lastsaved == 5) { newscript = "int1blue_5"; } state = 0; } obj.removetrigger(44); state = 0; break; case 45: //Generic "run script" if (obj.flags[65] == 0) { obj.changeflag(65, 1); startscript = true; if (lastsaved == 2) { newscript = "int1yellow_6"; } else if (lastsaved == 3) { newscript = "int1red_6"; } else if (lastsaved == 4) { newscript = "int1green_6"; } else if (lastsaved == 5) { newscript = "int1blue_6"; } state = 0; } obj.removetrigger(45); state = 0; break; case 46: //Generic "run script" if (obj.flags[66] == 0) { obj.changeflag(66, 1); startscript = true; if (lastsaved == 2) { newscript = "int1yellow_7"; } else if (lastsaved == 3) { newscript = "int1red_7"; } else if (lastsaved == 4) { newscript = "int1green_7"; } else if (lastsaved == 5) { newscript = "int1blue_7"; } state = 0; } obj.removetrigger(46); state = 0; break; case 47: //Generic "run script" if (obj.flags[69] == 0) { obj.changeflag(69, 1); startscript = true; newscript="trenchwarfare"; state = 0; } obj.removetrigger(47); state = 0; break; case 48: //Generic "run script" if (obj.flags[70] == 0) { obj.changeflag(70, 1); startscript = true; newscript="trinketcollector"; state = 0; } obj.removetrigger(48); state = 0; break; case 49: //Start final level music if (obj.flags[71] == 0) { obj.changeflag(71, 1); music.niceplay(15); //Final level remix state = 0; } obj.removetrigger(49); state = 0; break; case 50: music.playef(15, 10); dwgfx.createtextbox("Help! Can anyone hear", 35, 15, 255, 134, 255); dwgfx.addline("this message?"); dwgfx.textboxtimer(60); state++; statedelay = 100; break; case 51: music.playef(15, 10); dwgfx.createtextbox("Verdigris? Are you out", 30, 12, 255, 134, 255); dwgfx.addline("there? Are you ok?"); dwgfx.textboxtimer(60); state++; statedelay = 100; break; case 52: music.playef(15, 10); dwgfx.createtextbox("Please help us! We've crashed", 5, 22, 255, 134, 255); dwgfx.addline("and need assistance!"); dwgfx.textboxtimer(60); state++; statedelay = 100; break; case 53: music.playef(15, 10); dwgfx.createtextbox("Hello? Anyone out there?", 40, 15, 255, 134, 255); dwgfx.textboxtimer(60); state++; statedelay = 100; break; case 54: music.playef(15, 10); dwgfx.createtextbox("This is Doctor Violet from the", 5, 8, 255, 134, 255); dwgfx.addline("D.S.S. Souleye! Please respond!"); dwgfx.textboxtimer(60); state++; statedelay = 100; break; case 55: music.playef(15, 10); dwgfx.createtextbox("Please... Anyone...", 45, 14, 255, 134, 255); dwgfx.textboxtimer(60); state++; statedelay = 100; break; case 56: music.playef(15, 10); dwgfx.createtextbox("Please be alright, everyone...", 25, 18, 255, 134, 255); dwgfx.textboxtimer(60); state=50; statedelay = 100; break; case 80: //Used to return to menu from the game if(dwgfx.fademode == 1) state++; break; case 81: gamestate = 1; dwgfx.fademode = 4; music.play(6); dwgfx.backgrounddrawn = false; map.tdrawback = true; dwgfx.flipmode = false; createmenu("mainmenu"); state = 0; break; case 82: //Time Trial Complete! obj.removetrigger(82); hascontrol = false; timetrialresulttime = seconds + (minutes * 60); timetrialrank = 0; if (timetrialresulttime <= timetrialpar) timetrialrank++; if (trinkets >= timetrialshinytarget) timetrialrank++; if (deathcounts == 0) timetrialrank++; if (timetrialresulttime < besttimes[timetriallevel] || besttimes[timetriallevel]==-1) { besttimes[timetriallevel] = timetrialresulttime; } if (trinkets > besttrinkets[timetriallevel] || besttrinkets[timetriallevel]==-1) { besttrinkets[timetriallevel] = trinkets; } if (deathcounts < bestlives[timetriallevel] || bestlives[timetriallevel]==-1) { bestlives[timetriallevel] = deathcounts; } if (timetrialrank > bestrank[timetriallevel] || bestrank[timetriallevel]==-1) { bestrank[timetriallevel] = timetrialrank; if(timetrialrank>=3){ if(timetriallevel==0) NETWORK_unlockAchievement("vvvvvvtimetrial_station1_fixed"); if(timetriallevel==1) NETWORK_unlockAchievement("vvvvvvtimetrial_lab_fixed"); if(timetriallevel==2) NETWORK_unlockAchievement("vvvvvvtimetrial_tower_fixed"); if(timetriallevel==3) NETWORK_unlockAchievement("vvvvvvtimetrial_station2_fixed"); if(timetriallevel==4) NETWORK_unlockAchievement("vvvvvvtimetrial_warp_fixed"); if(timetriallevel==5) NETWORK_unlockAchievement("vvvvvvtimetrial_final_fixed"); } } savestats(map, dwgfx); dwgfx.fademode = 2; music.fadeout(); state++; break; case 83: frames--; if(dwgfx.fademode == 1) state++; break; case 84: dwgfx.flipmode = false; gamestate = 1; dwgfx.fademode = 4; dwgfx.backgrounddrawn = true; map.tdrawback = true; createmenu("timetrialcomplete"); state = 0; break; case 85: //Cutscene skip version of final level change obj.removetrigger(85); //Init final stretch state++; music.playef(9, 10); music.play(2); obj.flags[72] = 1; screenshake = 10; flashlight = 5; map.finalstretch = true; map.warpx = false; map.warpy = false; map.background = 6; map.final_colormode = true; map.final_colorframe = 1; state = 0; break; //From 90-100 are run scripts for the eurogamer expo only, remove later case 90: //Generic "run script" startscript = true; newscript="startexpolevel_station1"; obj.removetrigger(90); state = 0; break; case 91: //Generic "run script" startscript = true; newscript="startexpolevel_lab"; obj.removetrigger(91); state = 0; break; case 92: //Generic "run script" startscript = true; newscript="startexpolevel_warp"; obj.removetrigger(92); state = 0; break; case 93: //Generic "run script" startscript = true; newscript="startexpolevel_tower"; obj.removetrigger(93); state = 0; break; case 94: //Generic "run script" startscript = true; newscript="startexpolevel_station2"; obj.removetrigger(94); state = 0; break; case 95: //Generic "run script" startscript = true; newscript="startexpolevel_final"; obj.removetrigger(95); state = 0; break; case 96: //Used to return to gravitron to game if(dwgfx.fademode == 1) state++; break; case 97: gamestate = 0; dwgfx.fademode = 4; startscript = true; newscript="returntolab"; state = 0; break; case 100: // // Meeting crewmate in the warpzone // obj.removetrigger(100); if (obj.flags[4] == 0) { obj.changeflag(4, 1); state++; } break; case 101: { i = obj.getplayer(); hascontrol = false; if (obj.entities[i].onroof > 0 && gravitycontrol == 1) { gravitycontrol = 0; music.playef(1, 10); } if (obj.entities[i].onground > 0) { state++; } } break; case 102: { companion = 6; i = obj.getcompanion(6); obj.entities[i].tile = 0; obj.entities[i].state = 1; advancetext = true; hascontrol = false; dwgfx.createtextbox("Captain! I've been so worried!", 60, 90, 164, 255, 164); state++; music.playef(12, 10); } break; case 104: dwgfx.createtextbox("I'm glad you're ok!", 135, 152, 164, 164, 255); state++; music.playef(11, 10); dwgfx.textboxactive(); break; case 106: { dwgfx.createtextbox("I've been trying to find a", 74, 70, 164, 255, 164); dwgfx.addline("way out, but I keep going"); dwgfx.addline("around in circles..."); state++; music.playef(2, 10); dwgfx.textboxactive(); i = obj.getcompanion(6); obj.entities[i].tile = 54; obj.entities[i].state = 0; } break; case 108: dwgfx.createtextbox("Don't worry! I have a", 125, 152, 164, 164, 255); dwgfx.addline("teleporter key!"); state++; music.playef(11, 10); dwgfx.textboxactive(); break; case 110: { i = obj.getcompanion(6); obj.entities[i].tile = 0; obj.entities[i].state = 1; dwgfx.createtextbox("Follow me!", 185, 154, 164, 164, 255); state++; music.playef(11, 10); dwgfx.textboxactive(); } break; case 112: dwgfx.textboxremove(); hascontrol = true; advancetext = false; state = 0; break; case 115: // // Test script for space station, totally delete me! // { i = obj.getplayer(); hascontrol = false; state++; } break; case 116: advancetext = true; hascontrol = false; dwgfx.createtextbox("Sorry Eurogamers! Teleporting around", 60 - 20, 200, 255, 64, 64); dwgfx.addline("the map doesn't work in this version!"); dwgfx.textboxcenterx(); state++; break; case 118: dwgfx.textboxremove(); hascontrol = true; advancetext = false; state = 0; break; case 120: // // Meeting crewmate in the space station // obj.removetrigger(120); if (obj.flags[5] == 0) { obj.changeflag(5, 1); state++; } break; case 121: { i = obj.getplayer(); hascontrol = false; if (obj.entities[i].onground > 0 && gravitycontrol == 0) { gravitycontrol = 1; music.playef(1, 10); } if (obj.entities[i].onroof > 0) { state++; } } break; case 122: companion = 7; i = obj.getcompanion(7); obj.entities[i].tile = 6; obj.entities[i].state = 1; advancetext = true; hascontrol = false; dwgfx.createtextbox("Captain! You're ok!", 60-10, 90-40, 255, 255, 134); state++; music.playef(14, 10); break; case 124: dwgfx.createtextbox("I've found a teleporter, but", 60-20, 90 - 40, 255, 255, 134); dwgfx.addline("I can't get it to go anywhere..."); state++; music.playef(2, 10); dwgfx.textboxactive(); i = obj.getcompanion(7); //obj.entities[i].tile = 66; obj.entities[i].state = 0; break; case 126: dwgfx.createtextbox("I can help with that!", 125, 152-40, 164, 164, 255); state++; music.playef(11, 10); dwgfx.textboxactive(); break; case 128: dwgfx.createtextbox("I have the teleporter", 130, 152-35, 164, 164, 255); dwgfx.addline("codex for our ship!"); state++; music.playef(11, 10); dwgfx.textboxactive(); break; case 130: dwgfx.createtextbox("Yey! Let's go home!", 60-30, 90-35, 255, 255, 134); state++; music.playef(14, 10); dwgfx.textboxactive(); i = obj.getcompanion(7); obj.entities[i].tile = 6; obj.entities[i].state = 1; break; case 132: dwgfx.textboxremove(); hascontrol = true; advancetext = false; state = 0; break; case 200: //Init final stretch state++; music.playef(9, 10); //music.play(2); obj.flags[72] = 1; screenshake = 10; flashlight = 5; map.finalstretch = true; map.warpx = false; map.warpy = false; map.background = 6; map.final_colormode = true; map.final_colorframe = 1; startscript = true; newscript="finalterminal_finish"; state = 0; break; case 300: startscript = true; newscript="custom_"+customscript[0]; obj.removetrigger(300); state = 0; break; case 301: startscript = true; newscript="custom_"+customscript[1]; obj.removetrigger(301); state = 0; break; case 302: startscript = true; newscript="custom_"+customscript[2]; obj.removetrigger(302); state = 0; break; case 303: startscript = true; newscript="custom_"+customscript[3]; obj.removetrigger(303); state = 0; break; case 304: startscript = true; newscript="custom_"+customscript[4]; obj.removetrigger(304); state = 0; break; case 305: startscript = true; newscript="custom_"+customscript[5]; obj.removetrigger(305); state = 0; break; case 306: startscript = true; newscript="custom_"+customscript[6]; obj.removetrigger(306); state = 0; break; case 307: startscript = true; newscript="custom_"+customscript[7]; obj.removetrigger(307); state = 0; break; case 308: startscript = true; newscript="custom_"+customscript[8]; obj.removetrigger(308); state = 0; break; case 309: startscript = true; newscript="custom_"+customscript[9]; obj.removetrigger(309); state = 0; break; case 310: startscript = true; newscript="custom_"+customscript[10]; obj.removetrigger(310); state = 0; break; case 311: startscript = true; newscript="custom_"+customscript[11]; obj.removetrigger(311); state = 0; break; case 312: startscript = true; newscript="custom_"+customscript[12]; obj.removetrigger(312); state = 0; break; case 313: startscript = true; newscript="custom_"+customscript[13]; obj.removetrigger(313); state = 0; break; case 314: startscript = true; newscript="custom_"+customscript[14]; obj.removetrigger(314); state = 0; break; case 315: startscript = true; newscript="custom_"+customscript[15]; obj.removetrigger(315); state = 0; break; case 316: startscript = true; newscript="custom_"+customscript[16]; obj.removetrigger(316); state = 0; break; case 317: startscript = true; newscript="custom_"+customscript[17]; obj.removetrigger(317); state = 0; break; case 318: startscript = true; newscript="custom_"+customscript[18]; obj.removetrigger(318); state = 0; break; case 319: startscript = true; newscript="custom_"+customscript[19]; obj.removetrigger(319); state = 0; break; case 320: startscript = true; newscript="custom_"+customscript[20]; obj.removetrigger(320); state = 0; break; case 321: startscript = true; newscript="custom_"+customscript[21]; obj.removetrigger(321); state = 0; break; case 322: startscript = true; newscript="custom_"+customscript[22]; obj.removetrigger(322); state = 0; break; case 323: startscript = true; newscript="custom_"+customscript[23]; obj.removetrigger(323); state = 0; break; case 324: startscript = true; newscript="custom_"+customscript[24]; obj.removetrigger(324); state = 0; break; case 325: startscript = true; newscript="custom_"+customscript[25]; obj.removetrigger(325); state = 0; break; case 326: startscript = true; newscript="custom_"+customscript[26]; obj.removetrigger(326); state = 0; break; case 327: startscript = true; newscript="custom_"+customscript[27]; obj.removetrigger(327); state = 0; break; case 328: startscript = true; newscript="custom_"+customscript[28]; obj.removetrigger(328); state = 0; break; case 329: startscript = true; newscript="custom_"+customscript[29]; obj.removetrigger(329); state = 0; break; case 330: startscript = true; newscript="custom_"+customscript[30]; obj.removetrigger(330); state = 0; break; case 331: startscript = true; newscript="custom_"+customscript[31]; obj.removetrigger(331); state = 0; break; case 332: startscript = true; newscript="custom_"+customscript[32]; obj.removetrigger(332); state = 0; break; case 333: startscript = true; newscript="custom_"+customscript[33]; obj.removetrigger(333); state = 0; break; case 334: startscript = true; newscript="custom_"+customscript[34]; obj.removetrigger(334); state = 0; break; case 335: startscript = true; newscript="custom_"+customscript[35]; obj.removetrigger(335); state = 0; break; case 336: startscript = true; newscript="custom_"+customscript[36]; obj.removetrigger(336); state = 0; break; case 1000: dwgfx.showcutscenebars = true; hascontrol = false; completestop = true; state++; statedelay = 15; break; case 1001: //Found a trinket! advancetext = true; state++; if (dwgfx.flipmode) { dwgfx.createtextbox(" Congratulations! ", 50, 105, 174, 174, 174); dwgfx.addline(""); dwgfx.addline("You have found a shiny trinket!"); dwgfx.textboxcenterx(); if(map.custommode) { dwgfx.createtextbox(" " + help.number(trinkets) + " out of " + help.number(map.customtrinkets)+ " ", 50, 65, 174, 174, 174); dwgfx.textboxcenterx(); } else { dwgfx.createtextbox(" " + help.number(trinkets) + " out of Twenty ", 50, 65, 174, 174, 174); dwgfx.textboxcenterx(); } } else { dwgfx.createtextbox(" Congratulations! ", 50, 85, 174, 174, 174); dwgfx.addline(""); dwgfx.addline("You have found a shiny trinket!"); dwgfx.textboxcenterx(); if(map.custommode) { dwgfx.createtextbox(" " + help.number(trinkets) + " out of " + help.number(map.customtrinkets)+ " ", 50, 135, 174, 174, 174); dwgfx.textboxcenterx(); } else { dwgfx.createtextbox(" " + help.number(trinkets) + " out of Twenty ", 50, 135, 174, 174, 174); dwgfx.textboxcenterx(); } } break; case 1003: dwgfx.textboxremove(); hascontrol = true; advancetext = false; completestop = false; state = 0; //music.play(music.resumesong); if(!muted && music.currentsong>-1) music.fadeMusicVolumeIn(3000); dwgfx.showcutscenebars = false; break; case 1010: dwgfx.showcutscenebars = true; hascontrol = false; completestop = true; state++; statedelay = 15; break; case 1011: //Found a trinket! advancetext = true; state++; if (dwgfx.flipmode) { dwgfx.createtextbox(" Congratulations! ", 50, 105, 174, 174, 174); dwgfx.addline(""); dwgfx.addline("You have found a lost crewmate!"); dwgfx.textboxcenterx(); if(int(map.customcrewmates-crewmates)==0) { dwgfx.createtextbox(" All crewmates rescued! ", 50, 135, 174, 174, 174); } else if(map.customcrewmates-crewmates==1) { dwgfx.createtextbox(" " + help.number(int(map.customcrewmates-crewmates))+ " remains ", 50, 135, 174, 174, 174); } else { dwgfx.createtextbox(" " + help.number(int(map.customcrewmates-crewmates))+ " remain ", 50, 135, 174, 174, 174); } dwgfx.textboxcenterx(); } else { dwgfx.createtextbox(" Congratulations! ", 50, 85, 174, 174, 174); dwgfx.addline(""); dwgfx.addline("You have found a lost crewmate!"); dwgfx.textboxcenterx(); if(int(map.customcrewmates-crewmates)==0) { dwgfx.createtextbox(" All crewmates rescued! ", 50, 135, 174, 174, 174); } else if(map.customcrewmates-crewmates==1) { dwgfx.createtextbox(" " + help.number(int(map.customcrewmates-crewmates))+ " remains ", 50, 135, 174, 174, 174); } else { dwgfx.createtextbox(" " + help.number(int(map.customcrewmates-crewmates))+ " remain ", 50, 135, 174, 174, 174); } dwgfx.textboxcenterx(); } break; case 1013: dwgfx.textboxremove(); hascontrol = true; advancetext = false; completestop = false; state = 0; if(map.customcrewmates-crewmates==0) { if(map.custommodeforreal) { dwgfx.fademode = 2; if(!muted && ed.levmusic>0) music.fadeMusicVolumeIn(3000); if(ed.levmusic>0) music.fadeout(); state=1014; } else { gamestate = EDITORMODE; dwgfx.backgrounddrawn=false; if(!muted && ed.levmusic>0) music.fadeMusicVolumeIn(3000); if(ed.levmusic>0) music.fadeout(); } } else { if(!muted && ed.levmusic>0) music.fadeMusicVolumeIn(3000); } dwgfx.showcutscenebars = false; break; case 1014: frames--; if(dwgfx.fademode == 1) state++; break; case 1015: dwgfx.flipmode = false; gamestate = TITLEMODE; dwgfx.fademode = 4; music.play(6); dwgfx.backgrounddrawn = true; map.tdrawback = true; //Update level stats if(map.customcrewmates-crewmates==0) { //Finished level if(map.customtrinkets-trinkets==0) { //and got all the trinkets! updatecustomlevelstats(customlevelfilename, 3); } else { updatecustomlevelstats(customlevelfilename, 1); } } createmenu("levellist"); state = 0; break; case 2000: //Game Saved! if (intimetrial || nodeathmode || inintermission) { state = 0; } else { savetele(map, obj, music); if (dwgfx.flipmode) { dwgfx.createtextbox(" Game Saved ", -1, 202, 174, 174, 174); dwgfx.textboxtimer(25); } else { dwgfx.createtextbox(" Game Saved ", -1, 12, 174, 174, 174); dwgfx.textboxtimer(25); } state = 0; } break; case 2500: music.play(5); //Activating a teleporter (appear) state++; statedelay = 15; flashlight = 5; screenshake = 90; music.playef(9, 10); break; case 2501: //Activating a teleporter 2 state++; statedelay = 0; flashlight = 5; screenshake = 0; //we're done here! music.playef(10, 10); break; case 2502: //Activating a teleporter 2 state++; statedelay = 5; i = obj.getplayer(); obj.entities[i].colour = 0; obj.entities[i].invis = false; obj.entities[i].xp = obj.entities[obj.getteleporter()].xp+44; obj.entities[i].yp = obj.entities[obj.getteleporter()].yp+44; obj.entities[i].ay = -6; obj.entities[i].ax = 6; obj.entities[i].vy = -6; obj.entities[i].vx = 6; i = obj.getteleporter(); obj.entities[i].tile = 1; obj.entities[i].colour = 101; break; case 2503: state++; i = obj.getplayer(); obj.entities[i].xp += 10; break; case 2504: state++; i = obj.getplayer(); //obj.entities[i].xp += 10; break; case 2505: state++; i = obj.getplayer(); obj.entities[i].xp += 8; break; case 2506: state++; i = obj.getplayer(); obj.entities[i].xp += 6; break; case 2507: state++; i = obj.getplayer(); //obj.entities[i].xp += 4; break; case 2508: state++; i = obj.getplayer(); obj.entities[i].xp += 2; break; case 2509: state++; statedelay = 15; i = obj.getplayer(); obj.entities[i].xp += 1; break; case 2510: advancetext = true; hascontrol = false; dwgfx.createtextbox("Hello?", 125+24, 152-20, 164, 164, 255); state++; music.playef(11, 10); dwgfx.textboxactive(); break; case 2512: advancetext = true; hascontrol = false; dwgfx.createtextbox("Is anyone there?", 125+8, 152-24, 164, 164, 255); state++; music.playef(11, 10); dwgfx.textboxactive(); break; case 2514: dwgfx.textboxremove(); hascontrol = true; advancetext = false; state = 0; music.play(3); break; case 3000: //Activating a teleporter (long version for level complete) state++; statedelay = 30; flashlight = 5; screenshake = 90; music.playef(9, 10); break; case 3001: //Activating a teleporter 2 state++; statedelay = 15; flashlight = 5; music.playef(9, 10); break; case 3002: //Activating a teleporter 2 state++; statedelay = 15; flashlight = 5; music.playef(9, 10); break; case 3003: //Activating a teleporter 2 state++; statedelay = 15; flashlight = 5; music.playef(9, 10); break; case 3004: //Activating a teleporter 2 state++; statedelay = 0; flashlight = 5; screenshake = 0; //we're done here! music.playef(10, 10); break; case 3005: //Activating a teleporter 2 state++; statedelay = 50; //testing! //state = 3006; //Warp Zone //state = 3020; //Space Station switch(companion) { case 6: state = 3006; break; //Warp Zone case 7: state = 3020; break; //Space Station case 8: state = 3040; break; //Lab case 9: state = 3060; break; //Tower case 10: state = 3080; break; //Intermission 2 case 11: state = 3085; break; //Intermission 1 } i = obj.getplayer(); obj.entities[i].colour = 0; obj.entities[i].invis = true; i = obj.getcompanion(companion); if(i>-1) { obj.entities[i].active = false; } i = obj.getteleporter(); obj.entities[i].tile = 1; obj.entities[i].colour = 100; break; case 3006: //Level complete! (warp zone) unlocknum(4, map, dwgfx); lastsaved = 4; music.play(0); state++; statedelay = 75; if (dwgfx.flipmode) { dwgfx.createtextbox("", -1, 180, 165, 165, 255); } else { dwgfx.createtextbox("", -1, 12, 165, 165, 255); } //dwgfx.addline(" Level Complete! "); dwgfx.addline(" "); dwgfx.addline(""); dwgfx.addline(""); dwgfx.textboxcenterx(); /* advancetext = true; hascontrol = false; state = 3; dwgfx.createtextbox("To do: write quick", 50, 80, 164, 164, 255); dwgfx.addline("intro to story!");*/ break; case 3007: state++; statedelay = 45; if (dwgfx.flipmode) { dwgfx.createtextbox("", -1, 104, 175,174,174); } else { dwgfx.createtextbox("", -1, 64+8+16, 175,174,174); } dwgfx.addline(" You have rescued "); dwgfx.addline(" a crew member! "); dwgfx.addline(""); dwgfx.textboxcenterx(); break; case 3008: state++; statedelay = 45; temp = 6 - crewrescued(); if (temp == 1) { tempstring = " One remains "; if (dwgfx.flipmode) { dwgfx.createtextbox(tempstring, -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(tempstring, -1, 128+16, 174, 174, 174); } } else if (temp > 0) { tempstring = " " + help.number(temp) + " remain "; if (dwgfx.flipmode) { dwgfx.createtextbox(tempstring, -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(tempstring, -1, 128+16, 174, 174, 174); } } else { if (dwgfx.flipmode) { dwgfx.createtextbox(" All Crew Members Rescued! ", -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(" All Crew Members Rescued! ", -1, 128+16, 174, 174, 174); } } dwgfx.textboxcenterx(); break; case 3009: state++; statedelay = 0; if (dwgfx.flipmode) { dwgfx.createtextbox(" Press ACTION to continue ", -1, 20, 164, 164, 255); } else { dwgfx.createtextbox(" Press ACTION to continue ", -1, 196, 164, 164, 255); } dwgfx.textboxcenterx(); break; case 3010: if (jumppressed) { state++; statedelay = 30; dwgfx.textboxremove(); } break; case 3011: state = 3070; statedelay = 0; break; case 3020: //Level complete! (Space Station 2) unlocknum(3, map, dwgfx); lastsaved = 2; music.play(0); state++; statedelay = 75; if (dwgfx.flipmode) { dwgfx.createtextbox("", -1, 180, 165, 165, 255); } else { dwgfx.createtextbox("", -1, 12, 165, 165, 255); } //dwgfx.addline(" Level Complete! "); dwgfx.addline(" "); dwgfx.addline(""); dwgfx.addline(""); dwgfx.textboxcenterx(); /* advancetext = true; hascontrol = false; state = 3; dwgfx.createtextbox("To do: write quick", 50, 80, 164, 164, 255); dwgfx.addline("intro to story!");*/ break; case 3021: state++; statedelay = 45; if (dwgfx.flipmode) { dwgfx.createtextbox("", -1, 104, 174,175,174); } else { dwgfx.createtextbox("", -1, 64+8+16, 174,175,174); } dwgfx.addline(" You have rescued "); dwgfx.addline(" a crew member! "); dwgfx.addline(""); dwgfx.textboxcenterx(); break; case 3022: state++; statedelay = 45; temp = 6 - crewrescued(); if (temp == 1) { tempstring = " One remains "; if (dwgfx.flipmode) { dwgfx.createtextbox(tempstring, -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(tempstring, -1, 128+16, 174, 174, 174); } } else if (temp > 0) { tempstring = " " + help.number(temp) + " remain "; if (dwgfx.flipmode) { dwgfx.createtextbox(tempstring, -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(tempstring, -1, 128+16, 174, 174, 174); } } else { if (dwgfx.flipmode) { dwgfx.createtextbox(" All Crew Members Rescued! ", -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(" All Crew Members Rescued! ", -1, 128+16, 174, 174, 174); } } dwgfx.textboxcenterx(); break; case 3023: state++; statedelay = 0; if (dwgfx.flipmode) { dwgfx.createtextbox(" Press ACTION to continue ", -1, 20, 164, 164, 255); } else { dwgfx.createtextbox(" Press ACTION to continue ", -1, 196, 164, 164, 255); } dwgfx.textboxcenterx(); break; case 3024: if (jumppressed) { state++; statedelay = 30; dwgfx.textboxremove(); } break; case 3025: state = 3070; statedelay = 0; break; case 3040: //Level complete! (Lab) unlocknum(1, map, dwgfx); lastsaved = 5; music.play(0); state++; statedelay = 75; if (dwgfx.flipmode) { dwgfx.createtextbox("", -1, 180, 165, 165, 255); } else { dwgfx.createtextbox("", -1, 12, 165, 165, 255); } //dwgfx.addline(" Level Complete! "); dwgfx.addline(" "); dwgfx.addline(""); dwgfx.addline(""); dwgfx.textboxcenterx(); /* advancetext = true; hascontrol = false; state = 3; dwgfx.createtextbox("To do: write quick", 50, 80, 164, 164, 255); dwgfx.addline("intro to story!");*/ break; case 3041: state++; statedelay = 45; if (dwgfx.flipmode) { dwgfx.createtextbox("", -1, 104, 174,174,175); } else { dwgfx.createtextbox("", -1, 64+8+16, 174,174,175); } dwgfx.addline(" You have rescued "); dwgfx.addline(" a crew member! "); dwgfx.addline(""); dwgfx.textboxcenterx(); break; case 3042: state++; statedelay = 45; temp = 6 - crewrescued(); if (temp == 1) { tempstring = " One remains "; if (dwgfx.flipmode) { dwgfx.createtextbox(tempstring, -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(tempstring, -1, 128+16, 174, 174, 174); } } else if (temp > 0) { tempstring = " " + help.number(temp) + " remain "; if (dwgfx.flipmode) { dwgfx.createtextbox(tempstring, -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(tempstring, -1, 128+16, 174, 174, 174); } } else { if (dwgfx.flipmode) { dwgfx.createtextbox(" All Crew Members Rescued! ", -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(" All Crew Members Rescued! ", -1, 128+16, 174, 174, 174); } } dwgfx.textboxcenterx(); break; case 3043: state++; statedelay = 0; if (dwgfx.flipmode) { dwgfx.createtextbox(" Press ACTION to continue ", -1, 20, 164, 164, 255); } else { dwgfx.createtextbox(" Press ACTION to continue ", -1, 196, 164, 164, 255); } dwgfx.textboxcenterx(); break; case 3044: if (jumppressed) { state++; statedelay = 30; dwgfx.textboxremove(); } break; case 3045: state = 3070; statedelay = 0; break; case 3050: //Level complete! (Space Station 1) unlocknum(0, map, dwgfx); lastsaved = 1; music.play(0); state++; statedelay = 75; if (dwgfx.flipmode) { dwgfx.createtextbox("", -1, 180, 165, 165, 255); } else { dwgfx.createtextbox("", -1, 12, 165, 165, 255); } //dwgfx.addline(" Level Complete! "); dwgfx.addline(" "); dwgfx.addline(""); dwgfx.addline(""); dwgfx.textboxcenterx(); /* advancetext = true; hascontrol = false; state = 3; dwgfx.createtextbox("To do: write quick", 50, 80, 164, 164, 255); dwgfx.addline("intro to story!");*/ break; case 3051: state++; statedelay = 45; if (dwgfx.flipmode) { dwgfx.createtextbox("", -1, 104, 175,175,174); } else { dwgfx.createtextbox("", -1, 64+8+16, 175,175,174); } dwgfx.addline(" You have rescued "); dwgfx.addline(" a crew member! "); dwgfx.addline(""); dwgfx.textboxcenterx(); break; case 3052: state++; statedelay = 45; temp = 6 - crewrescued(); if (temp == 1) { tempstring = " One remains "; if (dwgfx.flipmode) { dwgfx.createtextbox(tempstring, -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(tempstring, -1, 128+16, 174, 174, 174); } } else if (temp > 0) { tempstring = " " + help.number(temp) + " remain "; if (dwgfx.flipmode) { dwgfx.createtextbox(tempstring, -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(tempstring, -1, 128+16, 174, 174, 174); } } else { if (dwgfx.flipmode) { dwgfx.createtextbox(" All Crew Members Rescued! ", -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(" All Crew Members Rescued! ", -1, 128+16, 174, 174, 174); } } dwgfx.textboxcenterx(); break; case 3053: state++; statedelay = 0; if (dwgfx.flipmode) { dwgfx.createtextbox(" Press ACTION to continue ", -1, 20, 164, 164, 255); } else { dwgfx.createtextbox(" Press ACTION to continue ", -1, 196, 164, 164, 255); } dwgfx.textboxcenterx(); break; case 3054: if (jumppressed) { state++; statedelay = 30; dwgfx.textboxremove(); crewstats[1] = 0; //Set violet's rescue script to 0 to make the next bit easier teleportscript = ""; } break; case 3055: dwgfx.fademode = 2; state++; statedelay = 10; break; case 3056: if(dwgfx.fademode==1) { startscript = true; if (nocutscenes) { newscript="bigopenworldskip"; } else { newscript = "bigopenworld"; } state = 0; } break; case 3060: //Level complete! (Tower) unlocknum(2, map, dwgfx); lastsaved = 3; music.play(0); state++; statedelay = 75; if (dwgfx.flipmode) { dwgfx.createtextbox("", -1, 180, 165, 165, 255); } else { dwgfx.createtextbox("", -1, 12, 165, 165, 255); } //dwgfx.addline(" Level Complete! "); dwgfx.addline(" "); dwgfx.addline(""); dwgfx.addline(""); dwgfx.textboxcenterx(); /* advancetext = true; hascontrol = false; state = 3; dwgfx.createtextbox("To do: write quick", 50, 80, 164, 164, 255); dwgfx.addline("intro to story!");*/ break; case 3061: state++; statedelay = 45; if (dwgfx.flipmode) { dwgfx.createtextbox("", -1, 104, 175,174,175); } else { dwgfx.createtextbox("", -1, 64+8+16, 175,174,175); } dwgfx.addline(" Y

Метки:  

CodeSOD: A Commentary on Military Force

Вторник, 22 Февраля 2022 г. 09:30 + в цитатник

Once upon a time, Simon worked for a company making software for missile systems. This was serious work, with serious testing procedures, and important standards around documentation.

Shortly before a live-fire test of a missile system, Simon knew better than to make any code changes, but he did want to improve the documentation. Adding comments was pretty low risk, so he went ahead and did that. By the time he was done, the Turbo Pascal code that controlled the missile looked like this:

{ add demands for pitch, yaw and roll, y x and z for this duty cycle } phidem := phidem + phidemc; psidem := psidem + psidemc; rdem := rdem + rdemc / 2; { NOTE: ROLL THRUSTERS MORE EFFICIENT THAN EXPECTED, CUT IT IN HALF zcdem := zcdem + zdemt[q]; { Add gravity over predicted velocity, from the table } ycdem := ycdem + ydemc; xcdem := xcdem + xdemc;

Specifically, it was the "magic number" of 2 that Simon wanted to explain. There was just one problem: he didn't terminate his comment. So the comment continued until the next }.

When the missile launched, it erupted from the tube, and then traced a perfect parabola into the dirt five meters in front of the launch tube.

It's unclear which was louder: the "thunk" sound of the missile striking the ground or Simon shouting an expletive when he realized his mistake.

[Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.

https://thedailywtf.com/articles/a-commentary-on-military-force


Метки:  

CodeSOD: Put Down the Pipe

Понедельник, 21 Февраля 2022 г. 09:30 + в цитатник

Camden's team works on an internal Angular application. Angular is constantly releasing new versions, and while they're largely backwards compatible, as the rule goes: every change breaks someone's workflow. Camden's team started to upgrade to Angular 12, only to discover that one of their dependencies wouldn't resolve. It refused to work with any version of Angular greater than 8.

The specific dependency promised to safely sanitize external resources, like DOM snippets and URLs fetched from an external source. At its core, it wrapped around the Angular DomSanitizer object, which provided all the plumbing for handling sanitization.

So the TypeScript method looked like this:

public safePipe(value: string, type: SafePipeType): SafeHtml | SafeStyle | SafeScript | SafeUrl | SafeResourceUrl { switch (type) { case 'html': return this.sanitizer.bypassSecurityTrustHtml(value); case 'style': return this.sanitizer.bypassSecurityTrustStyle(value); case 'script': return this.sanitizer.bypassSecurityTrustScript(value); case 'url': return this.sanitizer.bypassSecurityTrustUrl(value); case 'resourceUrl': return this.sanitizer.bypassSecurityTrustResourceUrl(value); default: throw new Error(`SafePipe unable to bypass security for invalid type: ${type}`); } } }

As you might guess from a method named bypassSecurityTrust…, this disables sanitization for that value. If anyone, in the future, calls sanitize on that value, no sanitization happens. So safePipe simply disables any security checks.

But let's just go to the Angular docs to see how they feel about this:

In specific situations, it might be necessary to disable sanitization, for example if the application genuinely needs to produce a javascript: style link with a dynamic value in it. Users can bypass security by constructing a value with one of the bypassSecurityTrust... methods, and then binding to that value from the template.
These situations should be very rare, and extraordinary care must be taken to avoid creating a Cross Site Scripting (XSS) security bug!
It is not required (and not recommended) to bypass security if the value is safe, e.g. a URL that does not start with a suspicious protocol, or an HTML snippet that does not contain dangerous code. The sanitizer leaves safe values intact.

Camden described this as the "least-applicable name" he'd seen in awhile.

[Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.

https://thedailywtf.com/articles/put-down-the-pipe


Метки:  

Error'd: In the fullness of time.

Пятница, 18 Февраля 2022 г. 09:30 + в цитатник

Regulargle Argle garbles "It's an advertisement. At least... it says so." Hey, if you can't believe advertisements, what can you believe?

advert

 

Time-traveling Kiwi Paul M. shares an adventure: "Notice the date in the menu bar. Presumably the covid passenger had booked a return sailing." Mumble mumble something international date line iwishalltimestampsincludedthebloodytimezone.

island

 

Yodeller Tom H. mutters "I look forward to receiving my parcel in n days time".

parcel

 

Opportunist Jeremy A. is being driven to a state of madness. "Don't worry, I tried entering my phone number too. Of course it says Error: You must enter a valid email address. " Excelsior!

capture

 

Marc W"urth posts practically parodically "Scott Adam's Dilbert website gave an error on the strip for today. But it could find one for this other day...". I was unable to reproduce this behavior, perhaps because the servers were full.

dilbert

 

[Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!

https://thedailywtf.com/articles/in-the-fullness-of-time


Метки:  

Поиск сообщений в rss_thedaily_wtf
Страницы: 124 ... 115 114 [113] 112 111 ..
.. 1 Календарь