What is the best method to determine file size resource usage in SenseNet? - sensenet

In order to charge appropriately for resource usage, i.e. database storage, we need to know the size of our client's files. Is there a simple way to calculate the resource usage for client's Workspace?

If you just want to know the size of the files in the workspace, you can use the funciton below, although total resource usage is likely much higher.
Calculate file size -- useful, but not close to total storage.
public static int DocumentFileSizeMB(string path)
{
var size = 0;
var results = ContentQuery.Query(SafeQueries.TypeInTree, null, "File", path);
if (results != null && results.Count > 0)
{
var longsize = results.Nodes.Sum(n => n.GetFullSize());
size = (int)(longsize / 1000000);
}
return size;
}
To get a better idea of storage space resources, call the SenseNet function GetTreeSize() on a node. However, this doesn't give the full resource usage due to other content that is related to the node size calcuation, but not stored beneath the node, such as Index tables, Log entries, etc.
A better method, but still not the full resource usage.
public static int NodeStorageSizeMB(string path)
{
var size = 0;
var node = Node.LoadNode(path);
if (node != null)
{
size = (int)(node.GetTreeSize() / 1000000); // Use 10**6 as Mega, not 1024*1024, which is "mebibyte".
}
return size;
}

Related

Vulkan depth image binding error

Hi I am trying to bind depth memory buffer but I get an error saying as below. I have no idea why this error is popping up.
The depth format is VK_FORMAT_D16_UNORM and the usage is VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT. I have read online that the TILING shouldnt be linear but then I get a different error. Thanks!!!
The code for creating and binding the image is as below.
VkImageCreateInfo imageInfo = {};
// If the depth format is undefined, use fallback as 16-byte value
if (Depth.format == VK_FORMAT_UNDEFINED) {
Depth.format = VK_FORMAT_D16_UNORM;
}
const VkFormat depthFormat = Depth.format;
VkFormatProperties props;
vkGetPhysicalDeviceFormatProperties(*deviceObj->gpu, depthFormat, &props);
if (props.linearTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
imageInfo.tiling = VK_IMAGE_TILING_LINEAR;
}
else if (props.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
}
else {
std::cout << "Unsupported Depth Format, try other Depth formats.\n";
exit(-1);
}
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
imageInfo.pNext = NULL;
imageInfo.imageType = VK_IMAGE_TYPE_2D;
imageInfo.format = depthFormat;
imageInfo.extent.width = width;
imageInfo.extent.height = height;
imageInfo.extent.depth = 1;
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = 1;
imageInfo.samples = NUM_SAMPLES;
imageInfo.queueFamilyIndexCount = 0;
imageInfo.pQueueFamilyIndices = NULL;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
imageInfo.flags = 0;
// User create image info and create the image objects
result = vkCreateImage(deviceObj->device, &imageInfo, NULL, &Depth.image);
assert(result == VK_SUCCESS);
// Get the image memory requirements
VkMemoryRequirements memRqrmnt;
vkGetImageMemoryRequirements(deviceObj->device, Depth.image, &memRqrmnt);
VkMemoryAllocateInfo memAlloc = {};
memAlloc.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
memAlloc.pNext = NULL;
memAlloc.allocationSize = 0;
memAlloc.memoryTypeIndex = 0;
memAlloc.allocationSize = memRqrmnt.size;
// Determine the type of memory required with the help of memory properties
pass = deviceObj->memoryTypeFromProperties(memRqrmnt.memoryTypeBits, 0, /* No requirements */ &memAlloc.memoryTypeIndex);
assert(pass);
// Allocate the memory for image objects
result = vkAllocateMemory(deviceObj->device, &memAlloc, NULL, &Depth.mem);
assert(result == VK_SUCCESS);
// Bind the allocated memeory
result = vkBindImageMemory(deviceObj->device, Depth.image, Depth.mem, 0);
assert(result == VK_SUCCESS);
Yes, linear tiling may not be supported for depth usage Images.
Consult the specification and Valid Usage section of VkImageCreateInfo. The capability is queried by vkGetPhysicalDeviceFormatProperties and vkGetPhysicalDeviceImageFormatProperties commands. Though depth formats are "opaque", so there is not much reason to use linear tiling.
This you seem to be doing in your code.
But the error informs you that you are trying to use a memory type that is not allowed for the given Image. Use vkGetImageMemoryRequirements command to query which memory types are allowed.
Possibly you have some error there (you are using 0x1 which is obviously not part of 0x84 per the message). You may want to reuse the example code in the Device Memory chapter of the specification. Provide your memoryTypeFromProperties implementation for more specific answer.
I accidentally set the typeIndex to 1 instead of i and it works now. In my defense I have been vulkan coding the whole day and my eyes are bleeding :). Thanks for the help.
bool VulkanDevice::memoryTypeFromProperties(uint32_t typeBits, VkFlags
requirementsMask, uint32_t *typeIndex)
{
// Search memtypes to find first index with those properties
for (uint32_t i = 0; i < 32; i++) {
if ((typeBits & 1) == 1) {
// Type is available, does it match user properties?
if ((memoryProperties.memoryTypes[i].propertyFlags & requirementsMask) == requirementsMask) {
*typeIndex = i;// was set to 1 :(
return true;
}
}
typeBits >>= 1;
}
// No memory types matched, return failure
return false;
}

Windows Store App: set an image as a background for an UI element

Sorry for asking a really basic question, but it's probably the first time for a number of years I feel really confused.
Windows provides two set of controls: Windows.UI.Xaml namespace (I thinks this is referred as Metro), used for Windows Store Apps, and System.Windows (WPF) for Desktop.
Since I am going to develop Windows Store Apps mainly for Windows 8.1 and Windows 10 phones, I will have to stick to Windows.UI.Xaml, and this has not only a separate set of UI elements, but also separate set of bitmaps, brushes, etc. (Windows.UI.Xaml.Media vs System.Windows.Media).
I found that Windows.UI.Xaml provides a very limited support for graphics, much less than provided by WPF, Android or (even!) iOS platform. To start with, I got stuck with a simple task: tiling a background!
Since Windows.UI.Xaml.Media.ImageBrush do not support tiling, I wanted to to do that "manually". Some sites suggest making numerous number of children, each holding a tile. Honestly, it looks as a rather awkward approach to me, so I decided to do it in what appears a more natural way: create an off-screen tiled image, assign it to a brush and assign the brush as the background for a panel.
The tiling code is rather straightforward (it probably has mistakes, possibly won't even not run on a phone, because of some unavailable classes used).
int panelWidth = (int) contentPanel.Width;
int panelHeight = (int) contentPanel.Height;
Bitmap bmpOffscreen = new Bitmap(panelWidth, panelHeight);
Graphics gOffscreen = Graphics.FromImage(bmpOffscreen);
string bmpPath = Path.Combine(Windows.ApplicationModel.Package.Current.InstalledLocation.Path, "Assets/just_a_tile.png");
System.Drawing.Image tile = System.Drawing.Image.FromFile(bmpPath, true);
int tileWidth = tile.Width;
int tileHeight = tile.Height;
for (int y = 0; y < panelHeight; y += tileHeight)
for (int x = 0; x < panelWidth; x += tileWidth)
gOffscreen.DrawImage(tile, x, y);
Now I presumably have the tiled image in bmpOffscreen. But how assign it to a brush? To do that I need to convert Bitmap to BitmapSource, while I couldn't find something similar to System.Windows.Imaging.CreateBitmapSourceFromHBitmap available for WPF structure!
Well, first of all System.Drawing namespace is not available in Windows Universal Platform, so you won't be able to use Bitmap class
But, all hope is not lost - you can use
Windows.UI.Xaml.Media.Imaging.WriteableBitmap
If you look at example included on this page, you will see that at one point image data is extracted to a byte array - all you need to do is copy it according to your needs
Please let me know if you want me to include a complete code sample.
Edit:
StorageFile file = await StorageFile.GetFileFromPathAsync(filePath);
Scenario4WriteableBitmap = new WriteableBitmap(2000, 2000);
// Ensure a file was selected
if (file != null)
{
using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
int columns = 4;
int rows = 4;
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(fileStream);
// Scale image to appropriate size
BitmapTransform transform = new BitmapTransform()
{
ScaledHeight = Convert.ToUInt32(Scenario4ImageContainer.Height),
ScaledWidth = Convert.ToUInt32(Scenario4ImageContainer.Width)
};
PixelDataProvider pixelData = await decoder.GetPixelDataAsync(
BitmapPixelFormat.Bgra8, // WriteableBitmap uses BGRA format
BitmapAlphaMode.Straight,
transform,
ExifOrientationMode.IgnoreExifOrientation, // This sample ignores Exif orientation
ColorManagementMode.DoNotColorManage);
// An array containing the decoded image data, which could be modified before being displayed
byte[] sourcePixels = pixelData.DetachPixelData();
// Open a stream to copy the image contents to the WriteableBitmap's pixel buffer
using (Stream stream = Scenario4WriteableBitmap.PixelBuffer.AsStream())
{
for (int i = 0; i < columns * rows; i++)
{
await stream.WriteAsync(sourcePixels, 0, sourcePixels.Length);
}
}
}
// Redraw the WriteableBitmap
Scenario4WriteableBitmap.Invalidate();
Scenario4Image.Source = Scenario4WriteableBitmap;
Scenario4Image.Stretch = Stretch.None;
}
Thank you, Arkadiusz. Since Australian time goes slightly ahead of Europe,
I had an advantage and seen the code before you posted it. I downloaded
MSDN XAML images sample and it helped me a lot. I gave a +1 to you but someone apparently put -1, so it compensated each other. Don't be upset I get -1 so often, that I stopped paying attention on that :)
So I've managed to do tiling with Windows Universal Platform! On my Lumia 532 phone it works magnifique. I felt like re-inventing a wheel, because all this stuff must be handled by SDK, not by a third-party developer.
public static async Task<bool> setupTiledBackground(Panel panel, string tilePath)
{
Brush backgroundBrush = await createTiledBackground((int)panel.Width, (int)panel.Height, TilePath);
if (backgroundBrush == null) return false;
panel.Background = backgroundBrush;
return true;
}
private static async Task<Brush> createTiledBackground(int width, int height, string tilePath)
{
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri("ms-appx:///" + tilePath));
byte[] sourcePixels;
int tileWidth, tileHeight;
using (IRandomAccessStream inputStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
if (inputStream == null) return null;
BitmapDecoder tileDecoder = await BitmapDecoder.CreateAsync(inputStream);
if (tileDecoder == null) return null;
tileWidth = (int)tileDecoder.PixelWidth;
tileHeight = (int) tileDecoder.PixelHeight;
PixelDataProvider pixelData = await tileDecoder.GetPixelDataAsync(
BitmapPixelFormat.Bgra8, // WriteableBitmap uses BGRA format
BitmapAlphaMode.Straight,
new BitmapTransform(),
ExifOrientationMode.IgnoreExifOrientation,
ColorManagementMode.DoNotColorManage);
sourcePixels = pixelData.DetachPixelData();
// fileStream.Dispose();
}
WriteableBitmap backgroundBitmap = new WriteableBitmap(width, height);
int tileBmpWidth = tileWidth << 2;
int screenBmpWidth = width << 2;
int tileSize = tileBmpWidth * tileHeight;
int sourceOffset = 0;
using (Stream outputStream = backgroundBitmap.PixelBuffer.AsStream())
{
for (int bmpY=0; bmpY < height; bmpY++) {
for (int bmpX = 0; bmpX < screenBmpWidth; bmpX += tileBmpWidth)
await outputStream.WriteAsync(sourcePixels, sourceOffset, Math.Min(screenBmpWidth - bmpX, tileBmpWidth));
if ((sourceOffset += tileBmpWidth) >= tileSize)
sourceOffset -= tileSize;
}
}
ImageBrush backgroundBrush = new ImageBrush();
backgroundBrush.ImageSource = backgroundBitmap; // It's very easy now!
return backgroundBrush; // Finita la comédia!
}
Just one remark: if you do it on form start, you should not wait for it.
This doesn't work:
public MainPage()
{
this.InitializeComponent();
bool result = setupTiledBackground(contextPanel, TilePath).Result;
}
This works:
private Task<bool> backgroundImageTask;
public MainPage()
{
this.InitializeComponent();
backgroundImageTask = setupTiledBackground(contextPanel, TilePath);
}

How to get document ID in CustomScoreProvider?

In short, I am trying to determine a document's true document ID in method CustomScoreProvider.CustomScore which only provides a document "ID" relative to a sub-IndexReader.
More info: I am trying to boost my documents' scores by precomputed boost factors (imagine an in-memory structure that maps Lucene's document ids to boost factors). Unfortunately I cannot store the boosts in the index for a couple of reasons: boosting will not be used for all queries, plus the boost factors can change regularly and that would trigger a lot of reindexing.
Instead I'd like to boost the score at query time and thus I've been working with CustomScoreQuery/CustomScoreProvider. The boosting takes place in method CustomScoreProvider.CustomScore:
public override float CustomScore(int doc, float subQueryScore, float valSrcScore) {
float baseScore = subQueryScore * valSrcScore; // the default computation
// boost -- THIS IS WHERE THE PROBLEM IS
float boostedScore = baseScore * MyBoostCache.GetBoostForDocId(doc);
return boostedScore;
}
My problem is with the doc parameter passed to CustomScore. It is not the true document id -- it is relative to the subreader used for that index segment. (The MyBoostCache class is my in-memory structure mapping Lucene's doc ids to boost factors.) If I knew the reader's docBase I could figure out the true id (id = doc + docBase).
Any thoughts on how I can determine the true id, or perhaps there's a better way to accomplish what I'm doing?
(I am aware that the id I'm trying to get is subject to change and I've already taken steps to make sure the MyBoostCache is always up to date with the latest ids.)
I was able to achieve this by passing the IndexSearcher to my CustomScoreProvider, using it to determine which of its subreaders is being used by the CustomScoreProvider, and then getting the MaxDoc for the prior subreaders from the IndexSearcher to determine the docBase.
private int DocBase { get; set; }
public MyScoreProvider(IndexReader reader, IndexSearcher searcher) {
DocBase = GetDocBaseForIndexReader(reader, searcher);
}
private static int GetDocBaseForIndexReader(IndexReader reader, IndexSearcher searcher) {
// get all segment readers for the searcher
IndexReader rootReader = searcher.GetIndexReader();
var subReaders = new List<IndexReader>();
ReaderUtil.GatherSubReaders(subReaders, rootReader);
// sequentially loop through the subreaders until we find the specified reader, adjusting our offset along the way
int docBase = 0;
for (int i = 0; i < subReaders.Count; i++)
{
if (subReaders[i] == reader)
break;
docBase += subReaders[i].MaxDoc();
}
return docBase;
}
public override float CustomScore(int doc, float subQueryScore, float valSrcScore) {
float baseScore = subQueryScore * valSrcScore;
float boostedScore = baseScore * MyBoostCache.GetBoostForDocId(doc + DocBase);
return boostedScore;
}

PHP running out of memory in all my scripts

EDIT:
My php.ini has 256MB memory set:
;;;;;;;;;;;;;;;;;;;
; Resource Limits ;
;;;;;;;;;;;;;;;;;;;
max_execution_time = 250 ; Maximum execution time of each script, in seconds
max_input_time = 120 ; Maximum amount of time each script may spend parsing request data
;max_input_nesting_level = 64 ; Maximum input variable nesting level
memory_limit = 256MB ; Maximum amount of memory a script may consume (256MB)
So I had a certain PHP script which was not very well written and when I executed it the PHP ran out of memory and my PC froze. Before running the script I have increased the memory limit in php.ini. I have changed it back to the default value after.
Now the problem is it seems to have done something to my PHP installation. Every PHP script I execute now is telling me it has not enough memmory. The scripts that have worked before without an issue.
It seems like the one bad script I mentioned earlier is still running in the background somehow.
I have restarted PHP, Apache, I have restarted my PC and even went to sleep for 8 hours. The next thing in the morning I find out all PHP scripts are still running out of memory. What the hell?
I am getting errors like this everywhere now (with the file in the error changing of course) - with every single even the simplest PHP script:
Fatal error: Allowed memory size of 262144 bytes exhausted (tried to allocate 6144 bytes) in D:\data\o\WebLib\src\Db\Db.php on line 241
Fatal error (shutdown): Allowed memory size of 262144 bytes exhausted (tried to allocate 6144 bytes) in D:\data\o\WebLib\src\Db\Db.php on line 241
Ok here is the script (I have commented out the bad parts):
<?php
error_reporting(E_ALL);
define('BASE_PATH', dirname(__FILE__));
require_once(BASE_PATH.'/../WebLib/config/paths.php');
require_once(PATH_TO_LIB3D_SRC.'/PHPExcel/Classes/PHPExcel.php');
require_once(PATH_TO_LIB3D_SRC.'/PHPExcel/Classes/PHPExcel/Reader/IReadFilter.php');
///** Define a Read Filter class implementing PHPExcel_Reader_IReadFilter */
//class chunkReadFilter implements PHPExcel_Reader_IReadFilter {
// private $_startRow = 0;
// private $_endRow = 0;
// /** Set the list of rows that we want to read */
// public function setRows($startRow, $chunkSize)
// {
// $this->_startRow = $startRow;
// $this->_endRow = $startRow + $chunkSize;
// }
// public function readCell($column, $row, $worksheetName = '')
// {
// // Only read the heading row, and the rows that are configured in $this->_startRow and $this->_endRow
// if (($row == 1) || ($row >= $this->_startRow && $row < $this->_endRow)) {
// return true;
// }
// return false;
// }
//}
//
//function ReadXlsxTableIntoArray($theFilePath)
//{
// $arrayData =
// $arrayOriginalColumnNames =
// $arrayColumnNames = array();
//
// $inputFileType = 'Excel2007';
// /** Create a new Reader of the type defined in $inputFileType **/
// $objReader = PHPExcel_IOFactory::createReader($inputFileType);
// /** Define how many rows we want to read for each "chunk" **/
// $chunkSize = 10;
// /** Create a new Instance of our Read Filter **/
// $chunkFilter = new chunkReadFilter();
// /** Tell the Reader that we want to use the Read Filter that we've Instantiated **/
// $objReader->setReadFilter($chunkFilter);
// $objReader->setReadDataOnly(true);
// /** Loop to read our worksheet in "chunk size" blocks **/
// /** $startRow is set to 2 initially because we always read the headings in row #1 **/
// for ($startRow = 1; $startRow <= 65536; $startRow += $chunkSize) {
// /** Tell the Read Filter, the limits on which rows we want to read this iteration **/
// $chunkFilter->setRows($startRow,$chunkSize);
// /** Load only the rows that match our filter from $inputFileName to a PHPExcel Object **/
// $objPHPExcel = $objReader->load($theFilePath);
// // Do some processing here
//
// $rowIterator = $objPHPExcel->getActiveSheet()->getRowIterator();
// foreach($rowIterator as $row){
//
// $cellIterator = $row->getCellIterator();
// //$cellIterator->setIterateOnlyExistingCells(false); // Loop all cells, even if it is not set
// if(1 == $row->getRowIndex ()) {
// foreach ($cellIterator as $cell) {
// $value = $cell->getCalculatedValue();
// $arrayOriginalColumnNames[] = $value;
// // let's remove the diacritique
// $value = iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $value);
// // and white spaces
// $valueExploded = explode(' ', $value);
// $value = '';
// // capitalize the first letter of each word
// foreach ($valueExploded as $word) {
// $value .= ucfirst($word);
// }
// $arrayColumnNames[] = $value;
// }
// continue;
// } else {
// $rowIndex = $row->getRowIndex();
// reset($arrayColumnNames);
// foreach ($cellIterator as $cell) {
// $arrayData[$rowIndex][current($arrayColumnNames)] = $cell->getCalculatedValue();
// next($arrayColumnNames);
// }
// }
//
// unset($cellIterator);
// }
//
// unset($rowIterator);
// }
//
// // Free up some of the memory
// $objPHPExcel->disconnectWorksheets();
// unset($objPHPExcel);
//
// return array($arrayOriginalColumnNames, $arrayColumnNames, $arrayData);
//}
//
//if (isset($_POST['uploadFile'])) {
// //list($tableOriginalColumnNames, $tableColumnNames, $tableData) = ReadXlsxTableIntoArray($_FILES['uploadedFile']['tmp_name']);
// //CreateXMLSchema($tableOriginalColumnNames, 'schema.xml');
// //echo GetReplaceDatabaseTableSQL('posta_prehlad_hp', $tableColumnNames, $tableData);
//}
Change the php.ini :
memory_limit = 256M
Note that you're not supposed to use MB or KB, but M or K
PHP expects the unit Megabyte to be denoted by the single letter M. You've specified 256MB. Notice the extra B.
Since PHP doesn't understand the unit MB, it falls back to the lowest known "named" unit: kilobyte (K).
Simply remove the extra B from your setting and it should properly read the value as 256 megabyte (256M)
Please see the following FAQ entry on data size units:
PHP: Using PHP - Manual
You have a memory_limit of 256K. Thats much to less in nearly all cases. The default value is 16M (since 5.2).
Are you sure you set your memory size back correctly? The error shows that your max memory is 262144 bytes, and that is a quarter of an MB. That's really low!
As reaction to your php settings: shouldn't that syntax be
memory_limit = 256M
I don't know if it accepts both M and MB, but it might not?
Hey Richard. The changes couldn't have been executed since PHP clearly states that you only have 256K set as limit. Look through the php.ini and all the other places. It could be located in a .htaccess file on the vhost/host.
Have you restarted Apache after you edited php.ini and increased the memory_limit = 256MB?

How to define end in objective C

OSStatus SetupBuffers(BG_FileInfo *inFileInfo)
{
int numBuffersToQueue = kNumberBuffers;
UInt32 maxPacketSize;
UInt32 size = sizeof(maxPacketSize);
// we need to calculate how many packets we read at a time, and how big a buffer we need
// we base this on the size of the packets in the file and an approximate duration for each buffer
// first check to see what the max size of a packet is - if it is bigger
// than our allocation default size, that needs to become larger
OSStatus result = AudioFileGetProperty(inFileInfo->mAFID, kAudioFilePropertyPacketSizeUpperBound, &size, &maxPacketSize);
AssertNoError("Error getting packet upper bound size", end);
bool isFormatVBR = (inFileInfo->mFileFormat.mBytesPerPacket == 0 || inFileInfo- >mFileFormat.mFramesPerPacket == 0);
CalculateBytesForTime(inFileInfo->mFileFormat, maxPacketSize, 0.5/*seconds*/, &mBufferByteSize, &mNumPacketsToRead);
// if the file is smaller than the capacity of all the buffer queues, always load it at once
if ((mBufferByteSize * numBuffersToQueue) > inFileInfo->mFileDataSize)
inFileInfo->mLoadAtOnce = true;
if (inFileInfo->mLoadAtOnce)
{
UInt64 theFileNumPackets;
size = sizeof(UInt64);
result = AudioFileGetProperty(inFileInfo->mAFID, kAudioFilePropertyAudioDataPacketCount, &size, &theFileNumPackets);
AssertNoError("Error getting packet count for file", end);***>>>>this is where xcode says undefined<<<<***
mNumPacketsToRead = (UInt32)theFileNumPackets;
mBufferByteSize = inFileInfo->mFileDataSize;
numBuffersToQueue = 1;
}
//Here is the exact error
label 'end' used but not defined
I have that error twice
If you look at the SoundEngine.cpp source that the snippet comes from, you'll see it's defined on the very next line:
end:
return result;
It's a label that execution jumps to when there's an error.
Uhm, the only place I can find AssertNoError is here in Technical Note TN2113. And it has a completely different format. AssertNoError(theError, "couldn't unregister the ABL"); Where is AssertNoError defined?
User #Jeremy P mentions this document as well.