<commit_before>/*This code is part of the Epoch Init System.
* The Epoch Init System is maintained by Subsentient.
* This software is public domain.
* Please read the file LICENSE.TXT for more information.*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
#include <pthread.h>
#include "epoch.h"

/**Globals**/

/*We store the current runlevel here.*/
char CurRunlevel[MAX_DESCRIPT_SIZE] = "default";
volatile unsigned long RunningChildCount = 0; /*How many child processes are running?
									* I promised myself I wouldn't use this code.*/

/**Function forward declarations.**/

static rStatus ExecuteConfigObject(ObjTable *InObj, Bool IsStartingMode);
static void *IndependentExecuteObject(void *InObj);


/**Actual functions.**/

static Bool FileUsable(const char *FileName)
{
	FILE *TS = fopen(FileName, "r");
	
	if (TS)
	{
		fclose(TS);
		return true;
	}
	else
	{
		return false;
	}
}

static void *IndependentExecuteObject(void *InObj)
{ /*Stub function for threading support.*/
	ExecuteConfigObject((ObjTable*)InObj, true);
	return NULL;
}

static rStatus ExecuteConfigObject(ObjTable *InObj, Bool IsStartingMode)
{ /*Not making static because this is probably going to be useful for other stuff.*/
	pid_t LaunchPID;
	const char *CurCmd, *ShellPath = "sh"; /*We try not to use absolute paths here, because some distros don't have normal layouts,
											*And I'm sure they would rather see a warning than have it just botch up.*/
	rStatus ExitStatus = FAILURE; /*We failed unless we succeeded.*/
	Bool ShellDissolves;
	int RawExitStatus;
	
	CurCmd = (IsStartingMode ? InObj->ObjectStartCommand : InObj->ObjectStopCommand);
	
	/*Check how we should handle PIDs for each shell. In order to get the PID, exit status,
	* and support shell commands, we need to jump through a bunch of hoops.
	* PID killing support in this manner, is buggy. That's why we support PIDFILE.*/
	if (FileUsable("/bin/bash"))
	{
		ShellDissolves = true;
		ShellPath = "bash";
	}
	else if (FileUsable("/bin/dash"))
	{
		ShellPath = "dash";
		ShellDissolves = true;
	}
	else if (FileUsable("/bin/zsh"))
	{
		ShellPath = "zsh";
		ShellDissolves = true;
	}
	else if (FileUsable("/bin/csh"))
	{
		ShellPath = "csh";
		ShellDissolves = true;
	}
	else if (FileUsable("/bin/busybox"))
	{ /*This is one of those weird shells that still does the old practice of creating a child for -c.
		* We can deal with the likes of them. Small chance that for shells like this, another PID could jump in front
		* and we could end up storing the wrong one. Very small, but possible.*/
		ShellPath = "busybox";
		ShellDissolves = false;
	}
#ifndef WEIRDSHELLPERMITTED
	else /*Found no other shells. Assume fossil, spit warning.*/
	{
		static Bool DidWarn = false; /*Don't spam this warning.*/
		
		ShellDissolves = false;
		if (!DidWarn)
		{	 
			DidWarn = true;
			SpitWarning("No known shell found. Using /bin/sh.\n"
			"Best if you install one of these: bash, dash, csh, zsh, or busybox.\n"
			"This matters because PID detection is affected by the way shells handle sh -c.");
		}
	}
#endif
	
	/**Here be where we execute commands.---------------**/
	
	LaunchPID = vfork();
	
	if (LaunchPID < 0)
	{
		SpitError("Failed to call vfork(). This is a critical error.");
		EmergencyShell();
	}
	
	if (LaunchPID > 0)
	{
			++RunningChildCount; /*I have a feeling that when the stars align,
								* this variable will be accessed by two threads at once
								* and crash to the ground. I hope I'm wrong.*/
	}
	
	if (LaunchPID == 0) /**Child process code.**/
	{ /*Child does all this.*/
		char TmpBuf[1024];
		
		/*Change our session id.*/
		setsid();
		
		execlp(ShellPath, "sh", "-c", CurCmd, NULL); /*I bet you think that this is going to return the PID of sh. No.*/
		/*We still around to talk about it? We were supposed to be imaged with the new command!*/
		
		snprintf(TmpBuf, 1024, "Failed to execute %s: execlp() failure.", InObj->ObjectID);
		SpitError(TmpBuf);
		EmergencyShell();
	}
	
	/**Parent code resumes.**/

	InObj->ObjectPID = LaunchPID; /*Save our PID.*/
	
	/*This code is really awful and somewhat unreliable, but hey, it's the price you pay for this support right now
	 * I'll implement a more reliable way eventually.*/
	
	if (!ShellDissolves)
	{
		++InObj->ObjectPID; /*This probably won't always work, but 99.9999999% of the time, yes, it will.*/
	}
	if (InObj->Opts.IsService)
	{ /*If we specify that this is a service, one up the PID again.*/
		++InObj->ObjectPID;
	}

	waitpid(LaunchPID, &RawExitStatus, 0); /*Wait for the process to exit.*/
	--RunningChildCount; /*We're done, so say so.*/
	
	/**And back to normalcy after this.------------------**/
	
	switch (WEXITSTATUS(RawExitStatus))
	{ /*FIXME: Make this do more later.*/
		case 128: /*Bad exit parameter*/
		case -1: /*Out of range for exit status. Probably shows as an unsigned value on some machines anyways.*/
			ExitStatus = WARNING;
			break;
		case 0:
			ExitStatus = SUCCESS;
			break;
		default:
			ExitStatus = FAILURE;
			break;
	}
	
	return ExitStatus;
}

rStatus ProcessConfigObject(ObjTable *CurObj, Bool IsStartingMode, Bool PrintStatus)
{
	char PrintOutStream[1024];
	rStatus ExitStatus = SUCCESS;
	
	if (IsStartingMode && *CurObj->ObjectStartCommand == '\0')
	{ /*Don't bother with it, if it has no command.
		For starting objects, this should not happen unless we set the option HALTONLY.*/
		return SUCCESS;
	}
	
	if (PrintStatus)
	{/*Copy in the description to be printed to the console.*/
		if (CurObj->Opts.RawDescription)
		{
			snprintf(PrintOutStream, 1024, "%s", CurObj->ObjectDescription);
		}
		else if (IsStartingMode && CurObj->Opts.NoWait)
		{
			snprintf(PrintOutStream, 1024, "%s %s", "Launching process for", CurObj->ObjectDescription);
		}
		else if (!IsStartingMode && CurObj->Opts.HaltCmdOnly)
		{
			snprintf(PrintOutStream, 1024, "%s %s", "Starting", CurObj->ObjectDescription);
		}
		else
		{
			snprintf(PrintOutStream, 1024, "%s %s", (IsStartingMode ? "Starting" : "Stopping"), CurObj->ObjectDescription);
		}
		
		if (IsStartingMode && CurObj->Opts.HaltCmdOnly)
		{
			PerformStatusReport(PrintOutStream, FAILURE, true);
			return FAILURE;
		}
	}
	
	if (IsStartingMode)
	{		
		if (PrintStatus)
		{
			printf("%s", PrintOutStream);
		}
		
		fflush(NULL); /*Things tend to get clogged up when we don't flush.*/
		
		if (CurObj->Opts.NoWait)
		{
			pthread_t MiniThread;
			
			pthread_create(&MiniThread, NULL, &IndependentExecuteObject, CurObj);
			pthread_detach(MiniThread);
			ExitStatus = NOTIFICATION;
		}
		else
		{
			
			ExitStatus = ExecuteConfigObject(CurObj, IsStartingMode);
		}
		
		CurObj->Started = (ExitStatus ? true : false); /*Mark the process dead or alive.*/
		
		if (PrintStatus)
		{
			PerformStatusReport(PrintOutStream, ExitStatus, true);
		}
	}
	else
	{		
		switch (CurObj->Opts.StopMode)
		{
			case STOP_COMMAND:
				if (PrintStatus)
				{
					printf("%s", PrintOutStream);
					fflush(NULL);
				}
				
				ExitStatus = ExecuteConfigObject(CurObj, IsStartingMode);
				CurObj->Started = (ExitStatus ? false : true); /*Mark the process dead.*/
				
				if (PrintStatus)
				{
					PerformStatusReport(PrintOutStream, ExitStatus, true);
				}
				break;
			case STOP_INVALID:
				break;
			case STOP_NONE:
				CurObj->Started = false; /*Just say we did it even if nothing to do.*/
				break;
			case STOP_PID:
				if (PrintStatus)
				{
					printf("%s", PrintOutStream);
					fflush(NULL);
				}
				
				if (kill(CurObj->ObjectPID, SIGTERM) == 0)
				{ /*Just send SIGTERM.*/
					ExitStatus = SUCCESS;
				}
				else
				{
					ExitStatus = FAILURE;
				}
				
				CurObj->Started = (ExitStatus ? false : true);
				
				if (PrintStatus)
				{
					PerformStatusReport(PrintOutStream, ExitStatus, true);
				}
				
				break;
			case STOP_PIDFILE:
			{
				FILE *Tdesc = fopen(CurObj->ObjectPIDFile, "r");
				unsigned long Inc = 0, TruePID = 0;
				char Buf[MAX_LINE_SIZE], WChar, *TWorker, *TW2;
				
				if (PrintStatus)
				{
					printf("%s", PrintOutStream);
					fflush(NULL);
				}
				
				for (; (WChar = getc(Tdesc)) != EOF && Inc < MAX_LINE_SIZE - 1; ++Inc)
				{
					Buf[Inc] = WChar;
				}
				Buf[Inc] = '\0'; /*Stop. Whining. About. The. Loops. I don't want to use stat() here!*/
				
				fclose(Tdesc);
			
				for (TWorker = Buf; *TWorker == '\t' || *TWorker == '\n' || *TWorker == ' '; ++TWorker); /*Skip past garbage.*/
				
				/*Delete extra junk characters at the end.*/
				for (TW2 = TWorker; *TW2 != '\0' && *TW2 != '\t' && *TW2 != '\n' && *TW2 != ' '; ++TW2);
				*TW2 = '\0';
				
				if (AllNumeric(TWorker))
				{
					TruePID = atoi(TWorker);
				}
				else
				{
					char TmpBuf[1024];
					
					snprintf(TmpBuf, 1024, "Cannot kill %s: The PID file does not contain purely numeric values.", CurObj->ObjectID);
					SpitError(TmpBuf);
					if (PrintStatus)
					{
						PerformStatusReport(PrintOutStream, FAILURE, true);
					}
					
					return WARNING;
				}
				
				/*Now we can actually kill the process ID.*/
				
				if (kill(TruePID, SIGTERM) == 0)
				{
					ExitStatus = SUCCESS;
				}
				else
				{
					ExitStatus = FAILURE;
				}
				CurObj->Started = (ExitStatus ? false : true);
				if (PrintStatus)
				{
					PerformStatusReport(PrintOutStream, ExitStatus, true);
				}
				
				break;
			}
		}
	}
	
	return ExitStatus;
}

/*This function does what it sounds like. It's not the entire boot sequence, we gotta display a message and stuff.*/
rStatus RunAllObjects(Bool IsStartingMode)
{
	unsigned long MaxPriority = GetHighestPriority(IsStartingMode);
	unsigned long Inc = 1; /*One to skip zero.*/
	ObjTable *CurObj = NULL;
	
	if (!MaxPriority && IsStartingMode)
	{
		SpitError("All objects have a priority of zero!");
		return FAILURE;
	}
	
	for (; Inc <= MaxPriority; ++Inc)
	{
		if (!(CurObj = GetObjectByPriority(IsStartingMode ? CurRunlevel : NULL, IsStartingMode, Inc)))
		{ /*Probably set to zero or something, but we don't care if we have a gap in the priority system.*/
			continue;
		}
		
		if (!CurObj->Enabled || CurObj->Opts.HaltCmdOnly)
		{
			continue;
		}
		
		if ((IsStartingMode ? !CurObj->Started : CurObj->Started))<commit_msg>Revert "Fix obsolete snippet in RunAllObjects()." This commit was erroneous and never should have made it in. This reverts commit 7<PASSWORD>.<commit_after>/*This code is part of the Epoch Init System.
* The Epoch Init System is maintained by Subsentient.
* This software is public domain.
* Please read the file LICENSE.TXT for more information.*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
#include <pthread.h>
#include "epoch.h"

/**Globals**/

/*We store the current runlevel here.*/
char CurRunlevel[MAX_DESCRIPT_SIZE] = "default";
volatile unsigned long RunningChildCount = 0; /*How many child processes are running?
									* I promised myself I wouldn't use this code.*/

/**Function forward declarations.**/

static rStatus ExecuteConfigObject(ObjTable *InObj, Bool IsStartingMode);
static void *IndependentExecuteObject(void *InObj);


/**Actual functions.**/

static Bool FileUsable(const char *FileName)
{
	FILE *TS = fopen(FileName, "r");
	
	if (TS)
	{
		fclose(TS);
		return true;
	}
	else
	{
		return false;
	}
}

static void *IndependentExecuteObject(void *InObj)
{ /*Stub function for threading support.*/
	ExecuteConfigObject((ObjTable*)InObj, true);
	return NULL;
}

static rStatus ExecuteConfigObject(ObjTable *InObj, Bool IsStartingMode)
{ /*Not making static because this is probably going to be useful for other stuff.*/
	pid_t LaunchPID;
	const char *CurCmd, *ShellPath = "sh"; /*We try not to use absolute paths here, because some distros don't have normal layouts,
											*And I'm sure they would rather see a warning than have it just botch up.*/
	rStatus ExitStatus = FAILURE; /*We failed unless we succeeded.*/
	Bool ShellDissolves;
	int RawExitStatus;
	
	CurCmd = (IsStartingMode ? InObj->ObjectStartCommand : InObj->ObjectStopCommand);
	
	/*Check how we should handle PIDs for each shell. In order to get the PID, exit status,
	* and support shell commands, we need to jump through a bunch of hoops.
	* PID killing support in this manner, is buggy. That's why we support PIDFILE.*/
	if (FileUsable("/bin/bash"))
	{
		ShellDissolves = true;
		ShellPath = "bash";
	}
	else if (FileUsable("/bin/dash"))
	{
		ShellPath = "dash";
		ShellDissolves = true;
	}
	else if (FileUsable("/bin/zsh"))
	{
		ShellPath = "zsh";
		ShellDissolves = true;
	}
	else if (FileUsable("/bin/csh"))
	{
		ShellPath = "csh";
		ShellDissolves = true;
	}
	else if (FileUsable("/bin/busybox"))
	{ /*This is one of those weird shells that still does the old practice of creating a child for -c.
		* We can deal with the likes of them. Small chance that for shells like this, another PID could jump in front
		* and we could end up storing the wrong one. Very small, but possible.*/
		ShellPath = "busybox";
		ShellDissolves = false;
	}
#ifndef WEIRDSHELLPERMITTED
	else /*Found no other shells. Assume fossil, spit warning.*/
	{
		static Bool DidWarn = false; /*Don't spam this warning.*/
		
		ShellDissolves = false;
		if (!DidWarn)
		{	 
			DidWarn = true;
			SpitWarning("No known shell found. Using /bin/sh.\n"
			"Best if you install one of these: bash, dash, csh, zsh, or busybox.\n"
			"This matters because PID detection is affected by the way shells handle sh -c.");
		}
	}
#endif
	
	/**Here be where we execute commands.---------------**/
	
	LaunchPID = vfork();
	
	if (LaunchPID < 0)
	{
		SpitError("Failed to call vfork(). This is a critical error.");
		EmergencyShell();
	}
	
	if (LaunchPID > 0)
	{
			++RunningChildCount; /*I have a feeling that when the stars align,
								* this variable will be accessed by two threads at once
								* and crash to the ground. I hope I'm wrong.*/
	}
	
	if (LaunchPID == 0) /**Child process code.**/
	{ /*Child does all this.*/
		char TmpBuf[1024];
		
		/*Change our session id.*/
		setsid();
		
		execlp(ShellPath, "sh", "-c", CurCmd, NULL); /*I bet you think that this is going to return the PID of sh. No.*/
		/*We still around to talk about it? We were supposed to be imaged with the new command!*/
		
		snprintf(TmpBuf, 1024, "Failed to execute %s: execlp() failure.", InObj->ObjectID);
		SpitError(TmpBuf);
		EmergencyShell();
	}
	
	/**Parent code resumes.**/

	InObj->ObjectPID = LaunchPID; /*Save our PID.*/
	
	/*This code is really awful and somewhat unreliable, but hey, it's the price you pay for this support right now
	 * I'll implement a more reliable way eventually.*/
	
	if (!ShellDissolves)
	{
		++InObj->ObjectPID; /*This probably won't always work, but 99.9999999% of the time, yes, it will.*/
	}
	if (InObj->Opts.IsService)
	{ /*If we specify that this is a service, one up the PID again.*/
		++InObj->ObjectPID;
	}

	waitpid(LaunchPID, &RawExitStatus, 0); /*Wait for the process to exit.*/
	--RunningChildCount; /*We're done, so say so.*/
	
	/**And back to normalcy after this.------------------**/
	
	switch (WEXITSTATUS(RawExitStatus))
	{ /*FIXME: Make this do more later.*/
		case 128: /*Bad exit parameter*/
		case -1: /*Out of range for exit status. Probably shows as an unsigned value on some machines anyways.*/
			ExitStatus = WARNING;
			break;
		case 0:
			ExitStatus = SUCCESS;
			break;
		default:
			ExitStatus = FAILURE;
			break;
	}
	
	return ExitStatus;
}

rStatus ProcessConfigObject(ObjTable *CurObj, Bool IsStartingMode, Bool PrintStatus)
{
	char PrintOutStream[1024];
	rStatus ExitStatus = SUCCESS;
	
	if (IsStartingMode && *CurObj->ObjectStartCommand == '\0')
	{ /*Don't bother with it, if it has no command.
		For starting objects, this should not happen unless we set the option HALTONLY.*/
		return SUCCESS;
	}
	
	if (PrintStatus)
	{/*Copy in the description to be printed to the console.*/
		if (CurObj->Opts.RawDescription)
		{
			snprintf(PrintOutStream, 1024, "%s", CurObj->ObjectDescription);
		}
		else if (IsStartingMode && CurObj->Opts.NoWait)
		{
			snprintf(PrintOutStream, 1024, "%s %s", "Launching process for", CurObj->ObjectDescription);
		}
		else if (!IsStartingMode && CurObj->Opts.HaltCmdOnly)
		{
			snprintf(PrintOutStream, 1024, "%s %s", "Starting", CurObj->ObjectDescription);
		}
		else
		{
			snprintf(PrintOutStream, 1024, "%s %s", (IsStartingMode ? "Starting" : "Stopping"), CurObj->ObjectDescription);
		}
		
		if (IsStartingMode && CurObj->Opts.HaltCmdOnly)
		{
			PerformStatusReport(PrintOutStream, FAILURE, true);
			return FAILURE;
		}
	}
	
	if (IsStartingMode)
	{		
		if (PrintStatus)
		{
			printf("%s", PrintOutStream);
		}
		
		fflush(NULL); /*Things tend to get clogged up when we don't flush.*/
		
		if (CurObj->Opts.NoWait)
		{
			pthread_t MiniThread;
			
			pthread_create(&MiniThread, NULL, &IndependentExecuteObject, CurObj);
			pthread_detach(MiniThread);
			ExitStatus = NOTIFICATION;
		}
		else
		{
			
			ExitStatus = ExecuteConfigObject(CurObj, IsStartingMode);
		}
		
		CurObj->Started = (ExitStatus ? true : false); /*Mark the process dead or alive.*/
		
		if (PrintStatus)
		{
			PerformStatusReport(PrintOutStream, ExitStatus, true);
		}
	}
	else
	{		
		switch (CurObj->Opts.StopMode)
		{
			case STOP_COMMAND:
				if (PrintStatus)
				{
					printf("%s", PrintOutStream);
					fflush(NULL);
				}
				
				ExitStatus = ExecuteConfigObject(CurObj, IsStartingMode);
				CurObj->Started = (ExitStatus ? false : true); /*Mark the process dead.*/
				
				if (PrintStatus)
				{
					PerformStatusReport(PrintOutStream, ExitStatus, true);
				}
				break;
			case STOP_INVALID:
				break;
			case STOP_NONE:
				CurObj->Started = false; /*Just say we did it even if nothing to do.*/
				break;
			case STOP_PID:
				if (PrintStatus)
				{
					printf("%s", PrintOutStream);
					fflush(NULL);
				}
				
				if (kill(CurObj->ObjectPID, SIGTERM) == 0)
				{ /*Just send SIGTERM.*/
					ExitStatus = SUCCESS;
				}
				else
				{
					ExitStatus = FAILURE;
				}
				
				CurObj->Started = (ExitStatus ? false : true);
				
				if (PrintStatus)
				{
					PerformStatusReport(PrintOutStream, ExitStatus, true);
				}
				
				break;
			case STOP_PIDFILE:
			{
				FILE *Tdesc = fopen(CurObj->ObjectPIDFile, "r");
				unsigned long Inc = 0, TruePID = 0;
				char Buf[MAX_LINE_SIZE], WChar, *TWorker, *TW2;
				
				if (PrintStatus)
				{
					printf("%s", PrintOutStream);
					fflush(NULL);
				}
				
				for (; (WChar = getc(Tdesc)) != EOF && Inc < MAX_LINE_SIZE - 1; ++Inc)
				{
					Buf[Inc] = WChar;
				}
				Buf[Inc] = '\0'; /*Stop. Whining. About. The. Loops. I don't want to use stat() here!*/
				
				fclose(Tdesc);
			
				for (TWorker = Buf; *TWorker == '\t' || *TWorker == '\n' || *TWorker == ' '; ++TWorker); /*Skip past garbage.*/
				
				/*Delete extra junk characters at the end.*/
				for (TW2 = TWorker; *TW2 != '\0' && *TW2 != '\t' && *TW2 != '\n' && *TW2 != ' '; ++TW2);
				*TW2 = '\0';
				
				if (AllNumeric(TWorker))
				{
					TruePID = atoi(TWorker);
				}
				else
				{
					char TmpBuf[1024];
					
					snprintf(TmpBuf, 1024, "Cannot kill %s: The PID file does not contain purely numeric values.", CurObj->ObjectID);
					SpitError(TmpBuf);
					if (PrintStatus)
					{
						PerformStatusReport(PrintOutStream, FAILURE, true);
					}
					
					return WARNING;
				}
				
				/*Now we can actually kill the process ID.*/
				
				if (kill(TruePID, SIGTERM) == 0)
				{
					ExitStatus = SUCCESS;
				}
				else
				{
					ExitStatus = FAILURE;
				}
				CurObj->Started = (ExitStatus ? false : true);
				if (PrintStatus)
				{
					PerformStatusReport(PrintOutStream, ExitStatus, true);
				}
				
				break;
			}
		}
	}
	
	return ExitStatus;
}

/*This function does what it sounds like. It's not the entire boot sequence, we gotta display a message and stuff.*/
rStatus RunAllObjects(Bool IsStartingMode)
{
	unsigned long MaxPriority = GetHighestPriority(IsStartingMode);
	unsigned long Inc = 1; /*One to skip zero.*/
	ObjTable *CurObj = NULL;
	
	if (!MaxPriority && IsStartingMode)
	{
		SpitError("All objects have a priority of zero!");
		return FAILURE;
	}
	
	for (; Inc <= MaxPriority; ++Inc)
	{
		if (!(CurObj = GetObjectByPriority(IsStartingMode ? CurRunlevel : NULL, IsStartingMode, Inc)))
		{ /*Probably set to zero or something, but we don't care if we have a gap in the priority system.*/
			continue;
		}
		
		if (!CurObj->Enabled || (IsStartingMode && CurObj->Opts.HaltCmdOnly))
		{
			continue;
		}
		
		if ((IsStartingMode ? !CurObj->Started : CurObj->Started))
{'fraction_non_alphanumeric': 0.12927479990298327, 'fraction_numerical': 0.007130730050933786, 'mean_word_length': 3.1133280127693537, 'pattern_counts': {'":': 0, '<': 28, '<?xml version=': 0, '>': 84, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5162124', 'n_tokens_mistral': 8291, 'n_tokens_neox': 6758, 'n_words': 2188}