/Arrays/Arrays.cs |
@@ -0,0 +1,133 @@ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2013 - License: GNU GPLv3 // |
// Please see: http://www.gnu.org/licenses/gpl.html for legal details, // |
// rights of fair usage, the disclaimer and warranty conditions. // |
/////////////////////////////////////////////////////////////////////////// |
|
using System; |
|
namespace wasSharp |
{ |
public static class Arrays |
{ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Gets an array element at a given modulo index. |
/// </summary> |
/// <typeparam name="T">the array type</typeparam> |
/// <param name="index">a positive or negative index of the element</param> |
/// <param name="data">the array</param> |
/// <return>an array element</return> |
public static T GetElementAt<T>(T[] data, int index) |
{ |
return index < 0 ? data[(index % data.Length + data.Length) % data.Length] : data[index % data.Length]; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Gets a sub-array from an array. |
/// </summary> |
/// <typeparam name="T">the array type</typeparam> |
/// <param name="data">the array</param> |
/// <param name="start">the start index</param> |
/// <param name="stop">the stop index (-1 denotes the end)</param> |
/// <returns>the array slice between start and stop</returns> |
public static T[] GetSubArray<T>(T[] data, int start, int stop) |
{ |
if (stop.Equals(-1)) |
stop = data.Length - 1; |
var result = new T[stop - start + 1]; |
Array.Copy(data, start, result, 0, stop - start + 1); |
return result; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Delete a sub-array and return the result. |
/// </summary> |
/// <typeparam name="T">the array type</typeparam> |
/// <param name="data">the array</param> |
/// <param name="start">the start index</param> |
/// <param name="stop">the stop index (-1 denotes the end)</param> |
/// <returns>the array without elements between start and stop</returns> |
public static T[] DeleteSubArray<T>(T[] data, int start, int stop) |
{ |
if (stop.Equals(-1)) |
stop = data.Length - 1; |
var result = new T[data.Length - (stop - start) - 1]; |
Array.Copy(data, 0, result, 0, start); |
Array.Copy(data, stop + 1, result, start, data.Length - stop - 1); |
return result; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Concatenate multiple arrays. |
/// </summary> |
/// <typeparam name="T">the array type</typeparam> |
/// <param name="arrays">multiple arrays</param> |
/// <returns>a flat array with all arrays concatenated</returns> |
public static T[] ConcatenateArrays<T>(params T[][] arrays) |
{ |
var resultLength = 0; |
foreach (var o in arrays) |
{ |
resultLength += o.Length; |
} |
var result = new T[resultLength]; |
var offset = 0; |
for (var x = 0; x < arrays.Length; x++) |
{ |
arrays[x].CopyTo(result, offset); |
offset += arrays[x].Length; |
} |
return result; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Permutes an array in reverse a given number of times. |
/// </summary> |
/// <typeparam name="T">the array type</typeparam> |
/// <param name="input">the array</param> |
/// <param name="times">the number of times to permute</param> |
/// <returns>the array with the elements permuted</returns> |
public static T[] ReversePermuteArrayElements<T>(T[] input, int times) |
{ |
if (times.Equals(0)) return input; |
var slice = new T[input.Length]; |
Array.Copy(input, 1, slice, 0, input.Length - 1); |
Array.Copy(input, 0, slice, input.Length - 1, 1); |
return ReversePermuteArrayElements(slice, --times); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Permutes an array forward a given number of times. |
/// </summary> |
/// <typeparam name="T">the array type</typeparam> |
/// <param name="input">the array</param> |
/// <param name="times">the number of times to permute</param> |
/// <returns>the array with the elements permuted</returns> |
public static T[] ForwardPermuteArrayElements<T>(T[] input, int times) |
{ |
if (times.Equals(0)) return input; |
var slice = new T[input.Length]; |
Array.Copy(input, input.Length - 1, slice, 0, 1); |
Array.Copy(input, 0, slice, 1, input.Length - 1); |
return ForwardPermuteArrayElements(slice, --times); |
} |
} |
} |
/Bit/BitTwiddling.cs |
@@ -0,0 +1,136 @@ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2013 - License: GNU GPLv3 // |
// Please see: http://www.gnu.org/licenses/gpl.html for legal details, // |
// rights of fair usage, the disclaimer and warranty conditions. // |
/////////////////////////////////////////////////////////////////////////// |
|
using System.Collections.Generic; |
using System.Linq; |
|
namespace wasSharp |
{ |
public static class BitTwiddling |
{ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Swaps two integers passed by reference using XOR. |
/// </summary> |
/// <param name="q">first integer to swap</param> |
/// <param name="p">second integer to swap</param> |
public static void XORSwap(ref int q, ref int p) |
{ |
q ^= p; |
p ^= q; |
q ^= p; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Checks whether a flag is set for a bitmask. |
/// </summary> |
/// <typeparam name="T">a data type</typeparam> |
/// <typeparam name="U">a data type</typeparam> |
/// <param name="mask">the mask to check the flag for</param> |
/// <param name="flag">the flag to check</param> |
/// <returns>true in case the flag is set</returns> |
public static bool IsMaskFlagSet<T, U>(this T mask, U flag) where T : struct where U : struct |
{ |
return unchecked(mask as dynamic & flag as dynamic) != 0; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Sets a flag for a bitmask. |
/// </summary> |
/// <typeparam name="T">a data type</typeparam> |
/// <typeparam name="U">a data type</typeparam> |
/// <param name="mask">the mask to set the flag on</param> |
/// <param name="flag">the flag to set</param> |
public static void SetMaskFlag<T, U>(ref T mask, U flag) where T : struct where U : struct |
{ |
mask = unchecked(mask as dynamic | flag as dynamic); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Create a bitmask from multiple flags. |
/// </summary> |
/// <typeparam name="T">a data type</typeparam> |
/// <param name="flag">the flags to set</param> |
/// <returns>a bitmask</returns> |
public static T CreateMask<T>(this IEnumerable<T> flag) where T : struct |
{ |
return flag.Aggregate((o, p) => unchecked(o as dynamic | p as dynamic)); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Unset a flag for a bitmask. |
/// </summary> |
/// <typeparam name="T">a data type</typeparam> |
/// <typeparam name="U">a data type</typeparam> |
/// <param name="mask">the mask to unset the flag on</param> |
/// <param name="flag">the flag to unset</param> |
public static void UnsetMaskFlag<T, U>(ref T mask, U flag) |
{ |
mask = unchecked(mask as dynamic & ~(flag as dynamic)); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Toggle a flag for a bitmask. |
/// </summary> |
/// <typeparam name="T">a data type</typeparam> |
/// <typeparam name="U">a data type</typeparam> |
/// <param name="mask">the mask to toggle the flag on</param> |
/// <param name="flag">the flag to toggle</param> |
public static void ToggleMaskFlag<T, U>(ref T mask, U flag) |
{ |
mask = unchecked(mask as dynamic ^ flag as dynamic); |
} |
|
/// <summary> |
/// Computes the previous power of two. |
/// </summary> |
/// <param name="x">the integer</param> |
/// <returns>the previous power of two</returns> |
/// <remarks>Adapted from Hacker's Delight ISBN-10:0201914654</remarks> |
public static T PreviousPowerOfTwo<T>(this T x) |
{ |
var y = x as dynamic; |
unchecked |
{ |
y = y | (y >> 1); |
y = y | (y >> 2); |
y = y | (y >> 4); |
y = y | (y >> 8); |
y = y | (y >> 16); |
return y - (y >> 1); |
} |
} |
|
/// <summary> |
/// Determines if a number is a power of two. |
/// </summary> |
/// <typeparam name="T">the number type</typeparam> |
/// <param name="x">the number</param> |
/// <returns>true of the number is a power of two</returns> |
public static bool IsPowerOfTwo<T>(this T x) |
{ |
var y = x as dynamic; |
return (y != 0) && ((y & (y - 1)) == 0); |
} |
} |
} |
/Cryptography/Cryptography.cs |
@@ -0,0 +1,395 @@ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2013 - License: GNU GPLv3 // |
// Please see: http://www.gnu.org/licenses/gpl.html for legal details, // |
// rights of fair usage, the disclaimer and warranty conditions. // |
/////////////////////////////////////////////////////////////////////////// |
|
using System; |
using System.Collections.Generic; |
using System.Linq; |
using System.Text; |
using System.Threading.Tasks; |
|
namespace wasSharp |
{ |
public static class Cryptography |
{ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Encrypt or decrypt a message given a set of rotors, plugs and a reflector. |
/// </summary> |
/// <param name="message">the message to encyrpt or decrypt</param> |
/// <param name="rotors">any combination of: 1, 2, 3, 4, 5, 6, 7, 8, b, g</param> |
/// <param name="plugs">the letter representing the start character for the rotor</param> |
/// <param name="reflector">any one of: B, b, C, c</param> |
/// <returns>either a decrypted or encrypted string</returns> |
public static string ENIGMA(string message, char[] rotors, char[] plugs, char reflector) |
{ |
var def_rotors = new Dictionary<char, char[]> |
{ |
{ |
'1', new[] |
{ |
'e', 'k', 'm', 'f', 'l', |
'g', 'd', 'q', 'v', 'z', |
'n', 't', 'o', 'w', 'y', |
'h', 'x', 'u', 's', 'p', |
'a', 'i', 'b', 'r', 'c', |
'j' |
} |
}, |
{ |
'2', new[] |
{ |
'a', 'j', 'd', 'k', 's', |
'i', 'r', 'u', 'x', 'b', |
'l', 'h', 'w', 't', 'm', |
'c', 'q', 'g', 'z', 'n', |
'p', 'y', 'f', 'v', 'o', |
'e' |
} |
}, |
{ |
'3', new[] |
{ |
'b', 'd', 'f', 'h', 'j', |
'l', 'c', 'p', 'r', 't', |
'x', 'v', 'z', 'n', 'y', |
'e', 'i', 'w', 'g', 'a', |
'k', 'm', 'u', 's', 'q', |
'o' |
} |
}, |
{ |
'4', new[] |
{ |
'e', 's', 'o', 'v', 'p', |
'z', 'j', 'a', 'y', 'q', |
'u', 'i', 'r', 'h', 'x', |
'l', 'n', 'f', 't', 'g', |
'k', 'd', 'c', 'm', 'w', |
'b' |
} |
}, |
{ |
'5', new[] |
{ |
'v', 'z', 'b', 'r', 'g', |
'i', 't', 'y', 'u', 'p', |
's', 'd', 'n', 'h', 'l', |
'x', 'a', 'w', 'm', 'j', |
'q', 'o', 'f', 'e', 'c', |
'k' |
} |
}, |
{ |
'6', new[] |
{ |
'j', 'p', 'g', 'v', 'o', |
'u', 'm', 'f', 'y', 'q', |
'b', 'e', 'n', 'h', 'z', |
'r', 'd', 'k', 'a', 's', |
'x', 'l', 'i', 'c', 't', |
'w' |
} |
}, |
{ |
'7', new[] |
{ |
'n', 'z', 'j', 'h', 'g', |
'r', 'c', 'x', 'm', 'y', |
's', 'w', 'b', 'o', 'u', |
'f', 'a', 'i', 'v', 'l', |
'p', 'e', 'k', 'q', 'd', |
't' |
} |
}, |
{ |
'8', new[] |
{ |
'f', 'k', 'q', 'h', 't', |
'l', 'x', 'o', 'c', 'b', |
'j', 's', 'p', 'd', 'z', |
'r', 'a', 'm', 'e', 'w', |
'n', 'i', 'u', 'y', 'g', |
'v' |
} |
}, |
{ |
'b', new[] |
{ |
'l', 'e', 'y', 'j', 'v', |
'c', 'n', 'i', 'x', 'w', |
'p', 'b', 'q', 'm', 'd', |
'r', 't', 'a', 'k', 'z', |
'g', 'f', 'u', 'h', 'o', |
's' |
} |
}, |
{ |
'g', new[] |
{ |
'f', 's', 'o', 'k', 'a', |
'n', 'u', 'e', 'r', 'h', |
'm', 'b', 't', 'i', 'y', |
'c', 'w', 'l', 'q', 'p', |
'z', 'x', 'v', 'g', 'j', |
'd' |
} |
} |
}; |
|
var def_reflectors = new Dictionary<char, char[]> |
{ |
{ |
'B', new[] |
{ |
'a', 'y', 'b', 'r', 'c', 'u', 'd', 'h', |
'e', 'q', 'f', 's', 'g', 'l', 'i', 'p', |
'j', 'x', 'k', 'n', 'm', 'o', 't', 'z', |
'v', 'w' |
} |
}, |
{ |
'b', new[] |
{ |
'a', 'e', 'b', 'n', 'c', 'k', 'd', 'q', |
'f', 'u', 'g', 'y', 'h', 'w', 'i', 'j', |
'l', 'o', 'm', 'p', 'r', 'x', 's', 'z', |
't', 'v' |
} |
}, |
{ |
'C', new[] |
{ |
'a', 'f', 'b', 'v', 'c', 'p', 'd', 'j', |
'e', 'i', 'g', 'o', 'h', 'y', 'k', 'r', |
'l', 'z', 'm', 'x', 'n', 'w', 't', 'q', |
's', 'u' |
} |
}, |
{ |
'c', new[] |
{ |
'a', 'r', 'b', 'd', 'c', 'o', 'e', 'j', |
'f', 'n', 'g', 't', 'h', 'k', 'i', 'v', |
'l', 'm', 'p', 'w', 'q', 'z', 's', 'x', |
'u', 'y' |
} |
} |
}; |
|
// Setup rotors from plugs. |
foreach (var rotor in rotors) |
{ |
var plug = plugs[Array.IndexOf(rotors, rotor)]; |
var i = Array.IndexOf(def_rotors[rotor], plug); |
if (i.Equals(0)) continue; |
def_rotors[rotor] = Arrays.ConcatenateArrays(new[] { plug }, |
Arrays.GetSubArray(Arrays.DeleteSubArray(def_rotors[rotor], i, i), i, -1), |
Arrays.GetSubArray(Arrays.DeleteSubArray(def_rotors[rotor], i + 1, -1), 0, i - 1)); |
} |
|
var result = new StringBuilder(); |
foreach (var c in message) |
{ |
if (!char.IsLetter(c)) |
{ |
result.Append(c); |
continue; |
} |
|
// Normalize to lower. |
var l = char.ToLower(c); |
|
Action<char[]> rotate = o => |
{ |
var i = o.Length - 1; |
do |
{ |
def_rotors[o[0]] = Arrays.ForwardPermuteArrayElements(def_rotors[o[0]], 1); |
if (i.Equals(0)) |
{ |
rotors = Arrays.ReversePermuteArrayElements(o, 1); |
continue; |
} |
l = Arrays.GetElementAt(def_rotors[o[1]], Array.IndexOf(def_rotors[o[0]], l) - 1); |
o = Arrays.ReversePermuteArrayElements(o, 1); |
} while (--i > -1); |
}; |
|
// Forward pass through the Enigma's rotors. |
rotate.Invoke(rotors); |
|
// Reflect |
var x = Array.IndexOf(def_reflectors[reflector], l); |
l = (x + 1) % 2 == 0 ? def_reflectors[reflector][x - 1] : def_reflectors[reflector][x + 1]; |
|
// Reverse the order of the rotors. |
Array.Reverse(rotors); |
|
// Reverse pass through the Enigma's rotors. |
rotate.Invoke(rotors); |
|
if (char.IsUpper(c)) |
{ |
l = char.ToUpper(l); |
} |
result.Append(l); |
} |
|
return result.ToString(); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Expand the VIGENRE key to the length of the input. |
/// </summary> |
/// <param name="input">the input to expand to</param> |
/// <param name="enc_key">the key to expand</param> |
/// <returns>the expanded key</returns> |
public static string VIGENEREExpandKey(string input, string enc_key) |
{ |
var exp_key = string.Empty; |
int i = 0, j = 0; |
do |
{ |
var p = input[i]; |
if (!char.IsLetter(p)) |
{ |
exp_key += p; |
++i; |
continue; |
} |
var m = j % enc_key.Length; |
exp_key += enc_key[m]; |
++j; |
++i; |
} while (i < input.Length); |
return exp_key; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Encrypt using VIGENERE. |
/// </summary> |
/// <param name="input">the input to encrypt</param> |
/// <param name="enc_key">the key to encrypt with</param> |
/// <returns>the encrypted input</returns> |
public static string EncryptVIGENERE(string input, string enc_key) |
{ |
char[] a = |
{ |
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', |
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' |
}; |
|
enc_key = VIGENEREExpandKey(input, enc_key); |
var result = string.Empty; |
var i = 0; |
do |
{ |
var p = input[i]; |
if (!char.IsLetter(p)) |
{ |
result += p; |
++i; |
continue; |
} |
var q = |
Arrays.ReversePermuteArrayElements(a, Array.IndexOf(a, enc_key[i]))[ |
Array.IndexOf(a, char.ToLowerInvariant(p))]; |
if (char.IsUpper(p)) |
{ |
q = char.ToUpperInvariant(q); |
} |
result += q; |
++i; |
} while (i < input.Length); |
return result; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2014 - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Decrypt using VIGENERE. |
/// </summary> |
/// <param name="input">the input to decrypt</param> |
/// <param name="enc_key">the key to decrypt with</param> |
/// <returns>the decrypted input</returns> |
public static string DecryptVIGENERE(string input, string enc_key) |
{ |
char[] a = |
{ |
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', |
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' |
}; |
|
enc_key = VIGENEREExpandKey(input, enc_key); |
var result = string.Empty; |
var i = 0; |
do |
{ |
var p = input[i]; |
if (!char.IsLetter(p)) |
{ |
result += p; |
++i; |
continue; |
} |
var q = |
a[ |
Array.IndexOf(Arrays.ReversePermuteArrayElements(a, Array.IndexOf(a, enc_key[i])), |
char.ToLowerInvariant(p))]; |
if (char.IsUpper(p)) |
{ |
q = char.ToUpperInvariant(q); |
} |
result += q; |
++i; |
} while (i < input.Length); |
return result; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2015 - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// An implementation of the ATBASH cypher for latin alphabets. |
/// </summary> |
/// <param name="data">the data to encrypt or decrypt</param> |
/// <returns>the encrypted or decrypted data</returns> |
public static string ATBASH(string data) |
{ |
char[] a = |
{ |
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', |
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' |
}; |
|
var input = data.ToCharArray(); |
|
Parallel.ForEach(Enumerable.Range(0, data.Length), i => |
{ |
var e = input[i]; |
if (!char.IsLetter(e)) return; |
var x = 25 - Array.BinarySearch(a, char.ToLowerInvariant(e)); |
if (!char.IsUpper(e)) |
{ |
input[i] = a[x]; |
return; |
} |
input[i] = char.ToUpperInvariant(a[x]); |
}); |
|
return new string(input); |
} |
} |
} |
/IO/IO.cs |
@@ -0,0 +1,177 @@ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2013 - License: GNU GPLv3 // |
// Please see: http://www.gnu.org/licenses/gpl.html for legal details, // |
// rights of fair usage, the disclaimer and warranty conditions. // |
/////////////////////////////////////////////////////////////////////////// |
|
using System.Collections.Generic; |
using System.IO; |
using System.IO.Compression; |
using System.Linq; |
using System.Text; |
using System.Threading.Tasks; |
|
namespace wasSharp |
{ |
public static class IO |
{ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Combine multiple paths. |
/// </summary> |
/// <param name="paths">an array of paths</param> |
/// <returns>a combined path</returns> |
public static string PathCombine(params string[] paths) |
{ |
return paths.Aggregate((x, y) => Path.Combine(x, y)); |
} |
|
/// <summary> |
/// Strip characters that are incompatible with file names. |
/// </summary> |
/// <param name="fileName">the name of the file</param> |
/// <returns>a clean string</returns> |
private static string CleanFileName(string fileName) |
{ |
return Path.GetInvalidFileNameChars() |
.Aggregate(fileName, (current, c) => current.Replace(c.ToString(), string.Empty)); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2017 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Compress a stream using Deflate compression. |
/// </summary> |
/// <param name="uncompressedSourceStream">the stream to compress</param> |
/// <param name="compressedDestinationStream">the stream to write the compressed stream to</param> |
/// <param name="leaveOpen">whether to leave the compression stream open</param> |
/// <returns>an awaitable Task</returns> |
public static async Task DeflateCompress(this Stream uncompressedSourceStream, |
Stream compressedDestinationStream, bool leaveOpen = false) |
{ |
using ( |
var compressionStream = new DeflateStream(compressedDestinationStream, CompressionMode.Compress, |
leaveOpen)) |
{ |
await uncompressedSourceStream.CopyToAsync(compressionStream); |
} |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2017 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Decompress a Deflate-compressed stream. |
/// </summary> |
/// <param name="compressedSourceStream">the compressed stream to decompress</param> |
/// <param name="uncompressedDestinationStream">the stream to write the decompressed stream to</param> |
/// <param name="leaveOpen">whether to leave the stream open after decompression</param> |
/// <returns>an awaitable Task</returns> |
public static async Task DeflateDecompress(this Stream compressedSourceStream, |
Stream uncompressedDestinationStream, bool leaveOpen = false) |
{ |
using ( |
var decompressionStream = new DeflateStream(compressedSourceStream, CompressionMode.Decompress, |
leaveOpen)) |
{ |
await decompressionStream.CopyToAsync(uncompressedDestinationStream); |
} |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2017 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Compress a stream using GZip compression. |
/// </summary> |
/// <param name="uncompressedSourceStream">the stream to compress</param> |
/// <param name="compressedDestinationStream">the stream to write the compressed stream to</param> |
/// <param name="leaveOpen">whether to leave the stream open after compressing</param> |
/// <returns>an awaitable Task</returns> |
public static async Task GZipCompress(this Stream uncompressedSourceStream, Stream compressedDestinationStream, |
bool leaveOpen = false) |
{ |
using ( |
var compressionStream = new GZipStream(compressedDestinationStream, CompressionMode.Compress, leaveOpen) |
) |
{ |
await uncompressedSourceStream.CopyToAsync(compressionStream); |
} |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2017 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Decompress a GZiped stream. |
/// </summary> |
/// <param name="compressedSourceStream">the stream to decompress</param> |
/// <param name="uncompressedDestinationStream">the stream to write the decompressed stream to</param> |
/// <param name="leaveOpen">whether the decompression stream should be left open</param> |
/// <returns>an awaitable Task</returns> |
public static async Task GZipDecompress(this Stream compressedSourceStream, Stream uncompressedDestinationStream, |
bool leaveOpen = false) |
{ |
using ( |
var decompressionStream = new GZipStream(compressedSourceStream, CompressionMode.Decompress, leaveOpen)) |
{ |
await decompressionStream.CopyToAsync(uncompressedDestinationStream); |
} |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Splits a path using a separator and an escape character. |
/// </summary> |
/// <param name="path">the path to split</param> |
/// <param name="separator">the separator character</param> |
/// <param name="escape">the escape character</param> |
/// <param name="includeRootSeparator">true if the initial separator should be included</param> |
/// <returns>path parts</returns> |
public static IEnumerable<string> PathSplit(this string path, char separator, char? escape = null, bool includeRootSeparator = true) |
{ |
var s = new Stack<char>(); |
var p = new StringBuilder(); |
foreach (var c in path) |
{ |
if (c.Equals(escape)) |
{ |
s.Push(c); |
continue; |
} |
if (c.Equals(separator)) |
{ |
if (s.Count.Equals(0) || !s.Peek().Equals(escape)) |
{ |
if (p.Length.Equals(0) && includeRootSeparator) |
{ |
p.Append(c); |
continue; |
} |
yield return p.ToString(); |
p = new StringBuilder(); |
continue; |
} |
s.Pop(); |
while (!s.Count.Equals(0)) |
{ |
p.Append(s.Pop()); |
} |
p.Append(c); |
continue; |
} |
p.Append(c); |
} |
while (!s.Count.Equals(0)) |
{ |
p.Append(s.Pop()); |
} |
yield return p.ToString(); |
} |
} |
} |
/Lambda/Linq.cs |
@@ -0,0 +1,353 @@ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2013 - License: GNU GPLv3 // |
// Please see: http://www.gnu.org/licenses/gpl.html for legal details, // |
// rights of fair usage, the disclaimer and warranty conditions. // |
/////////////////////////////////////////////////////////////////////////// |
|
using System; |
using System.Collections.Generic; |
using System.Linq; |
|
namespace wasSharp.Linq |
{ |
public static class Extensions |
{ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2017 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// A functional implementation of a switch clause. |
/// </summary> |
/// <typeparam name="T">the type of items in the query</typeparam> |
/// <param name="query">the selector query</param> |
/// <param name="default">the function to execute when no case matches</param> |
/// <param name="case">a list of predicates representing the switch cases, |
/// where each predicate has to return True or False indicating whether |
/// fallthrough should occur. |
/// </param> |
/// <remarks>when used, the default action must be explicitly specified |
/// due to language restrictions |
/// </remarks> |
public static void Switch<T>(this IEnumerable<T> query, |
// default |
Action<T> @default, |
// case |
// case |
// ... |
params Predicate<T>[] @case) |
{ |
if (@case.Length % 2 != 0) |
throw new ArgumentException("Pairs of predicates expected."); |
|
var enumerable = query as IList<T> ?? query.ToList(); |
using (var iter = enumerable.GetEnumerator()) |
{ |
while (iter.MoveNext()) |
{ |
var match = false; |
for (var i = 0; i < @case.Length; i += 2) |
{ |
if (!@case[i].Invoke(iter.Current)) |
continue; |
|
if (@case[i + 1].Invoke(iter.Current)) |
return; |
|
match = true; |
} |
|
if (!match) |
@default.Invoke(iter.Current); |
} |
} |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2017 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// A functional implementation of a switch clause. |
/// </summary> |
/// <typeparam name="T">the type of the item to query</typeparam> |
/// <param name="query">the selector query</param> |
/// <param name="default">the function to execute when no case matches</param> |
/// <param name="case">a list of predicates representing the switch cases, |
/// where each predicate has to return True or False indicating whether |
/// fallthrough should occur. |
/// </param> |
/// <remarks>when used, the default action must be explicitly specified |
/// due to language restrictions |
/// </remarks> |
public static void Switch<T>(this T query, |
// default |
Action<T> @default, |
// case |
// case |
// ... |
params Predicate<T>[] @case) |
{ |
if (@case.Length % 2 != 0) |
throw new ArgumentException("Pairs of predicates expected."); |
|
var match = false; |
for (var i = 0; i < @case.Length; i += 2) |
{ |
if (!@case[i].Invoke(query)) |
continue; |
|
if (@case[i + 1].Invoke(query)) |
return; |
|
match = true; |
} |
|
if (!match) |
@default.Invoke(query); |
|
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2017 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Invokes pf in case the predicate p resolves or qf in case the predicate q resolves, or ef otherwise. |
/// </summary> |
/// <typeparam name="T">the type of items in the query</typeparam> |
/// <param name="query">the selector query</param> |
/// <param name="p">the condition for invoking pf</param> |
/// <param name="pf">the action to invoke in case p resolves</param> |
/// <param name="q">the condition for invoking qf</param> |
/// <param name="qf">the action to invoke in case q resolves</param> |
/// <param name="ef">the action to invoke otherwise</param> |
public static void ForAll<T>(this ParallelQuery<T> query, Predicate<T> p, Action<T> pf, Predicate<T> q, Action<T> qf, Action<T> ef) |
{ |
query.ForAll(o => |
{ |
if (p.Invoke(o)) |
{ |
pf.Invoke(o); |
} |
else if (q.Invoke(o)) |
{ |
qf.Invoke(o); |
} |
else |
{ |
ef.Invoke(o); |
} |
}); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2017 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Invokes pf in case the predicate p resolves or qf in case the predicate q resolves. |
/// </summary> |
/// <typeparam name="T">the type of items in the query</typeparam> |
/// <param name="query">the selector query</param> |
/// <param name="p">the condition for invoking pf</param> |
/// <param name="pf">the action to invoke in case p resolves</param> |
/// <param name="q">the condition for invoking qf</param> |
/// <param name="qf">the action to invoke in case q resolves</param> |
public static void ForAll<T>(this ParallelQuery<T> query, Predicate<T> p, Action<T> pf, Predicate<T> q, Action<T> qf) |
{ |
query.ForAll(o => |
{ |
if (p.Invoke(o)) |
{ |
pf.Invoke(o); |
return; |
} |
|
if (q.Invoke(o)) |
{ |
qf.Invoke(o); |
return; |
} |
}); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2017 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Invokes pass if and only if predicate resovles or fail otherwise. |
/// </summary> |
/// <typeparam name="T">the type of items in the query</typeparam> |
/// <param name="query">the selector query</param> |
/// <param name="condition">the condition for invoking pf</param> |
/// <param name="pass">the function to invoke in case the predicate resolves</param> |
/// <param name="fail">the function to invoke otherwise</param> |
public static void ForAll<T>(this ParallelQuery<T> query, Predicate<T> condition, Action<T> pass, Action<T> fail) |
{ |
query.ForAll(o => |
{ |
switch (condition.Invoke(o)) |
{ |
case true: |
pass.Invoke(o); |
return; |
|
default: |
fail.Invoke(o); |
return; |
} |
}); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2017 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Invokes pass if and only if condition holds or fail otherwise. |
/// </summary> |
/// <typeparam name="T">the return type of the pass and fail functions</typeparam> |
/// <param name="condition">the branch condition</param> |
/// <param name="pass">function with no parameters and return type T in case condition passes</param> |
/// <param name="fail">function with no parameters and return type T in case condition fails</param> |
/// <returns>the result of pass in case condition holds or the result of fail otherwise</returns> |
public static T IfElse<T>(this bool condition, Func<T> pass, Func<T> fail) |
{ |
return condition ? pass.Invoke() : fail.Invoke(); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2017 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Invokes pass if and only if condition holds or fail otherwise. |
/// </summary> |
/// <typeparam name="U">the type of the argument to pass and fail</typeparam> |
/// <typeparam name="V">the return type of pass and fail</typeparam> |
/// <param name="condition">the branch condition</param> |
/// <param name="pass">function that takes argument arg and returns type V in case condition holds</param> |
/// <param name="fail">function that takes argument arg and returns type V in case condition fails</param> |
/// <param name="arg">the argument passed to pass or fail functions</param> |
/// <returns>the result of pass in case condition holds or the result of fail otherwise</returns> |
public static V IfElse<U, V>(this bool condition, Func<U, V> pass, Func<U, V> fail, U arg = default(U)) |
{ |
return condition ? pass.Invoke(arg) : fail.Invoke(arg); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2017 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Invokes pass if and only if condition holds or fail otherwise. |
/// </summary> |
/// <typeparam name="T">the type of the argument to pass and fail</typeparam> |
/// <param name="condition">the branch condition</param> |
/// <param name="pass">function that takes argument arg and returns nothing in case condition holds</param> |
/// <param name="fail">function that takes argument arg and returns nothing in case condition fails</param> |
/// <param name="arg">the optional argument passed to pass or fail functions</param> |
public static void IfElse<T>(this bool condition, Action<T> pass, Action<T> fail, T arg = default(T)) |
{ |
switch (condition) |
{ |
case true: |
pass.Invoke(arg); |
return; |
|
default: |
fail.Invoke(arg); |
return; |
} |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2017 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Invokes pass if and only if condition holds or fail otherwise. |
/// </summary> |
/// <typeparam name="U">the type of the first argument to the pass or fail functions</typeparam> |
/// <typeparam name="V">the type of the second argument to the pass or fail functions</typeparam> |
/// <param name="condition">the branch condition</param> |
/// <param name="pass">function that takes argument arg and returns nothing in case condition holds</param> |
/// <param name="fail">function that takes argument arg and returns nothing in case condition fails</param> |
/// <param name="arga">first optional argument passed to pass or fail functions</param> |
/// <param name="argb">second optional argument passed to pass or fail functions</param> |
public static void IfElse<U, V>(this bool condition, Action<U, V> pass, Action<U, V> fail, U arga = default(U), V argb = default(V)) |
{ |
switch (condition) |
{ |
case true: |
pass.Invoke(arga, argb); |
return; |
|
default: |
fail.Invoke(arga, argb); |
return; |
} |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Returns true of an enumerable contains more than one element. |
/// </summary> |
/// <typeparam name="T">the type of the enumeration</typeparam> |
/// <param name="e">the enumeration</param> |
/// <returns>true if enumeration contains more than one element</returns> |
/// <remarks>O(2) worst case</remarks> |
public static bool Some<T>(this IEnumerable<T> e) |
{ |
var i = 0; |
using (var iter = e.GetEnumerator()) |
{ |
while (iter.MoveNext()) |
{ |
if (++i > 1) |
return true; |
} |
return false; |
} |
} |
|
/// <summary> |
/// Sequentially removes all the elements from the first sequence that are in the second sequence |
/// or all the elements from the second sequence that are in the first sequence. |
/// </summary> |
/// <typeparam name="T">the type o the collection</typeparam> |
/// <param name="o">the first sequence to remove from</param> |
/// <param name="p">the second sequence to remove</param> |
/// <returns>the first sequence excluding the second sequence or the second sequence excluding the first sequence</returns> |
public static IEnumerable<T> SequenceExceptAny<T>(this IEnumerable<T> o, IEnumerable<T> p) where T : IEquatable<T> |
{ |
var l = new List<T>(o); |
var r = new List<T>(p); |
return l.Count > r.Count |
? l.Zip(r, (x, y) => x.Equals(y) ? default(T) : y) |
.Concat(l.Skip(r.Count)) |
.Where(q => q != null && !q.Equals(default(T))) |
: r.Zip(l, (x, y) => x.Equals(y) ? default(T) : y) |
.Concat(r.Skip(l.Count)) |
.Where(q => q != null && !q.Equals(default(T))); |
} |
|
/// <summary> |
/// Sequentially removes all the elements from the first sequence that are in the second sequence. |
/// </summary> |
/// <typeparam name="T">the type o the collection</typeparam> |
/// <param name="o">the first sequence to remove from</param> |
/// <param name="p">the second sequence to remove</param> |
/// <returns>the first sequence excluding the second sequence</returns> |
public static IEnumerable<T> SequenceExcept<T>(this IEnumerable<T> a, IEnumerable<T> b) where T : IEquatable<T> |
{ |
using (var ea = a.GetEnumerator()) |
{ |
using (var eb = b.GetEnumerator()) |
{ |
while (ea.MoveNext()) |
{ |
if (eb.MoveNext() && ea.Current.Equals(eb.Current)) |
continue; |
yield return ea.Current; |
} |
} |
} |
} |
} |
} |
/Languages/CSV.cs |
@@ -0,0 +1,140 @@ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2013 - License: GNU GPLv3 // |
// Please see: http://www.gnu.org/licenses/gpl.html for legal details, // |
// rights of fair usage, the disclaimer and warranty conditions. // |
/////////////////////////////////////////////////////////////////////////// |
|
using System.Collections.Generic; |
using System.Linq; |
using System.Text; |
|
namespace wasSharp |
{ |
public static class CSV |
{ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Converts a list of strings to a comma-separated values string. |
/// </summary> |
/// <returns>a commma-separated list of values</returns> |
/// <remarks>compliant with RFC 4180</remarks> |
public static string FromEnumerable(IEnumerable<string> input) |
{ |
return string.Join(",", |
input |
.Select(o => o.Replace("\"", "\"\"")) |
.Select(o => o.IndexOfAny(new[] { '"', ' ', ',', '\r', '\n' }).Equals(-1) ? o : "\"" + o + "\"")); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Converts a dictionary of strings to a comma-separated values string. |
/// </summary> |
/// <returns>a commma-separated list of values</returns> |
/// <remarks>compliant with RFC 4180</remarks> |
public static string FromDictionary<K, V>(Dictionary<K, V> input) |
{ |
return string.Join(",", input.Keys.Select(o => o.ToString()).Zip(input.Values.Select(o => o.ToString()), |
(o, p) => |
string.Join(",", |
o.Replace("\"", "\"\"").IndexOfAny(new[] { '"', ' ', ',', '\r', '\n' }).Equals(-1) |
? o |
: "\"" + o + "\"", |
p.Replace("\"", "\"\"").IndexOfAny(new[] { '"', ' ', ',', '\r', '\n' }).Equals(-1) |
? p |
: "\"" + p + "\""))); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Converts successive comma-separated values to key-value pairs. |
/// </summary> |
/// <returns>key-value pairs of successive comma-separate values</returns> |
public static IEnumerable<KeyValuePair<string, string>> ToKeyValue(string input) |
{ |
return ToEnumerable(input).AsParallel().Select((o, p) => new { o, p }) |
.GroupBy(q => q.p / 2, q => q.o) |
.Select(o => o.ToArray()) |
.TakeWhile(o => o.Length % 2 == 0) |
.Where(o => !string.IsNullOrEmpty(o[0])) |
.Select(o => new KeyValuePair<string, string>(o[0], o[1])); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Converts a generic key value pair to a CSV. |
/// </summary> |
/// <returns>a commma-separated list of values</returns> |
/// <remarks>compliant with RFC 4180</remarks> |
public static string FromKeyValue<K, V>(KeyValuePair<K, V> input) |
{ |
var key = input.Key.ToString(); |
var value = input.Value.ToString(); |
|
return string.Join(",", key |
.Replace("\"", "\"\"").IndexOfAny(new[] { '"', ' ', ',', '\r', '\n' }).Equals(-1) |
? key |
: "\"" + key + "\"", value |
.Replace("\"", "\"\"") |
.IndexOfAny(new[] { '"', ' ', ',', '\r', '\n' }) |
.Equals(-1) |
? value |
: "\"" + value + "\""); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Converts a comma-separated list of values to a list of strings. |
/// </summary> |
/// <param name="csv">a comma-separated list of values</param> |
/// <returns>a list of strings</returns> |
/// <remarks>compliant with RFC 4180</remarks> |
public static IEnumerable<string> ToEnumerable(string csv) |
{ |
var s = new Stack<char>(); |
var m = new StringBuilder(); |
for (var i = 0; i < csv.Length; ++i) |
{ |
switch (csv[i]) |
{ |
case ',': |
if (!s.Any() || !s.Peek().Equals('"')) |
{ |
yield return m.ToString(); |
m = new StringBuilder(); |
continue; |
} |
m.Append(csv[i]); |
continue; |
case '"': |
if (i + 1 < csv.Length && csv[i].Equals(csv[i + 1])) |
{ |
m.Append(csv[i]); |
++i; |
continue; |
} |
if (!s.Any() || !s.Peek().Equals(csv[i])) |
{ |
s.Push(csv[i]); |
continue; |
} |
s.Pop(); |
continue; |
} |
m.Append(csv[i]); |
} |
|
yield return m.ToString(); |
} |
} |
} |
/Languages/KeyValue.cs |
@@ -0,0 +1,125 @@ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2013 - License: GNU GPLv3 // |
// Please see: http://www.gnu.org/licenses/gpl.html for legal details, // |
// rights of fair usage, the disclaimer and warranty conditions. // |
/////////////////////////////////////////////////////////////////////////// |
|
using System; |
using System.Collections.Generic; |
using System.Linq; |
|
namespace wasSharp |
{ |
public static class KeyValue |
{ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Returns the value of a key from a key-value data string. |
/// </summary> |
/// <returns>true if the key was found in data</returns> |
public static string Get(string key, string data) |
{ |
return data.Split('&') |
.AsParallel() |
.Select(o => o.Split('=')) |
.Where(o => o.Length.Equals(2) && string.Equals(o[0], key, StringComparison.Ordinal)) |
.Select(o => o[1]) |
.FirstOrDefault(); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Returns a key-value data string with a key set to a given value. |
/// </summary> |
/// <returns> |
/// a key-value data string or the empty string if either key or |
/// value are empty |
/// </returns> |
public static string Set(string key, string value, string data) |
{ |
return string.Join("&", string.Join("&", data.Split('&') |
.AsParallel() |
.Select(o => o.Split('=')) |
.Where(o => o.Length.Equals(2) && !string.Equals(o[0], key, StringComparison.Ordinal)) |
.Select(o => string.Join("=", o[0], o[1]))), string.Join("=", key, value)); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Deletes a key-value pair from a string referenced by a key. |
/// </summary> |
/// <returns>a key-value pair string</returns> |
public static string Delete(string key, string data) |
{ |
return string.Join("&", data.Split('&') |
.AsParallel() |
.Select(o => o.Split('=')) |
.Where(o => o.Length.Equals(2) && !string.Equals(o[0], key, StringComparison.Ordinal)) |
.Select(o => string.Join("=", o[0], o[1]))); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Decodes key-value pair data to a dictionary. |
/// </summary> |
/// <returns>a dictionary containing the keys and values</returns> |
public static Dictionary<string, string> Decode(string data) |
{ |
return data.Split('&') |
.AsParallel() |
.Select(o => o.Split('=')) |
.Where(o => o.Length.Equals(2)) |
.Select(o => new |
{ |
k = o[0], |
v = o[1] |
}) |
.GroupBy(o => o.k) |
.ToDictionary(o => o.Key, p => p.FirstOrDefault()?.v); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Serialises a dictionary to key-value data. |
/// </summary> |
/// <returns>a key-value data encoded string</returns> |
public static string Encode(Dictionary<string, string> data) |
{ |
return string.Join("&", data.AsParallel().Select(o => string.Join("=", o.Key, o.Value))); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Serialises a dictionary to key-value data. |
/// </summary> |
/// <returns>a key-value data encoded string</returns> |
public static string Encode(IEnumerable<KeyValuePair<string, string>> data) |
{ |
return string.Join("&", data.AsParallel().Select(o => string.Join("=", o.Key, o.Value))); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Escapes a dictionary's keys and values for sending as POST data. |
/// </summary> |
public static IEnumerable<KeyValuePair<string, string>> Escape(IEnumerable<KeyValuePair<string, string>> data, |
Func<string, string> func) |
{ |
return data.AsParallel().ToDictionary(o => func(o.Key), p => func(p.Value)); |
} |
} |
} |
/Languages/XML.cs |
@@ -0,0 +1,189 @@ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2013 - License: GNU GPLv3 // |
// Please see: http://www.gnu.org/licenses/gpl.html for legal details, // |
// rights of fair usage, the disclaimer and warranty conditions. // |
/////////////////////////////////////////////////////////////////////////// |
|
using System; |
using System.Collections.Generic; |
using System.Linq; |
using System.Linq.Expressions; |
using System.Text; |
using System.Text.RegularExpressions; |
using System.Threading.Tasks; |
using System.Xml.Linq; |
|
namespace wasSharp |
{ |
public static class XML |
{ |
private static readonly Func<string, bool> directIsSafeXML = |
((Expression<Func<string, bool>>) |
(data => |
Regex.Replace(data, |
@"(" + string.Join(@"|", @"&", @"<", @">", @""", @"'") + @")", |
@"", RegexOptions.IgnoreCase | RegexOptions.Multiline) |
.IndexOfAny(new[] { '&', '<', '>', '"', '\'' }) |
.Equals(-1))).Compile(); |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Unescapes a string used in XML. |
/// </summary> |
/// <param name="s">the string to unescape</param> |
/// <returns>an XML unescaped string</returns> |
public static string UnescapeXML(string s) |
{ |
var t = new Queue<char>(); |
var m = new StringBuilder(); |
foreach (var c in s) |
{ |
switch (c) |
{ |
case '&': |
if (!t.Count.Equals(0)) |
{ |
m.Append(string.Join("", t.ToArray())); |
t.Clear(); |
} |
t.Enqueue(c); |
break; |
|
case ';': |
if (!t.Count.Equals(0)) |
{ |
t.Enqueue(c); |
var special = string.Join("", t.ToArray()); |
switch (special) |
{ |
case "'": |
m.Append('\''); |
break; |
|
case """: |
m.Append('"'); |
break; |
|
case ">": |
m.Append('>'); |
break; |
|
case "<": |
m.Append('<'); |
break; |
|
case "&": |
m.Append('&'); |
break; |
|
default: // Unrecognized escape sequence |
m.Append(special); |
break; |
} |
t.Clear(); |
break; |
} |
m.Append(c); |
break; |
|
default: |
if (!t.Count.Equals(0)) |
{ |
t.Enqueue(c); |
if (t.Count >= 6) |
{ |
m.Append(string.Join("", t.ToArray())); |
t.Clear(); |
} |
break; |
} |
m.Append(c); |
break; |
} |
} |
return m.ToString(); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Escapes a string to be used in XML. |
/// </summary> |
/// <param name="s">the string to escape</param> |
/// <returns>an XML escaped string</returns> |
public static string EscapeXML(string s) |
{ |
if (string.IsNullOrEmpty(s)) return s; |
|
var result = new string[s.Length]; |
Parallel.ForEach(Enumerable.Range(0, s.Length), o => |
{ |
switch (s[o]) |
{ |
case '&': |
result[o] = @"&"; |
break; |
|
case '<': |
result[o] = @"<"; |
break; |
|
case '>': |
result[o] = @">"; |
break; |
|
case '"': |
result[o] = @"""; |
break; |
|
case '\'': |
result[o] = @"'"; |
break; |
|
default: |
result[o] = s[o].ToString(); |
break; |
} |
}); |
return string.Join("", result); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Determines whether a string is safe to use in XML |
/// </summary> |
/// <param name="data">the string to check</param> |
/// <returns>true in case the string is safe</returns> |
public static bool IsSafeXML(string data) |
{ |
return directIsSafeXML(data); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Recursively rename a node by name. |
/// </summary> |
/// <param name="root">the root from where to start</param> |
/// <param name="name">the name to replace</param> |
/// <param name="rename">the name to replace with</param> |
public static void RenameNodes(XElement root, string name, string rename) |
{ |
if (string.Equals(root.Name.LocalName, name, StringComparison.Ordinal)) |
{ |
root.Name = rename; |
} |
|
foreach (var xElement in root.Elements()) |
{ |
RenameNodes(xElement, name, rename); |
} |
} |
} |
} |
/Reflection/Reflection.cs |
@@ -0,0 +1,320 @@ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) Wizardry and Steamworks 2013 - License: GNU GPLv3 // |
// Please see: http://www.gnu.org/licenses/gpl.html for legal details, // |
// rights of fair usage, the disclaimer and warranty conditions. // |
/////////////////////////////////////////////////////////////////////////// |
|
using System; |
using System.Collections.Generic; |
using System.Linq; |
using System.Reflection; |
|
namespace wasSharp |
{ |
public static class Reflection |
{ |
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Retrieves an attribute of type T from an enumeration. |
/// </summary> |
/// <returns>an attribute of type T</returns> |
public static T GetAttributeFromEnumValue<T>(Enum value) where T : Attribute |
{ |
return (T)value.GetType() |
.GetRuntimeField(value.ToString()) |
.GetCustomAttributes(typeof(T), false) |
.SingleOrDefault(); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Returns all the attributes of type T of an enumeration. |
/// </summary> |
/// <typeparam name="T">the attribute to retrieve</typeparam> |
/// <returns>a list of attributes</returns> |
public static IEnumerable<T> GetEnumAttributes<T>(Enum e) where T : Attribute |
{ |
return e.GetType().GetRuntimeFields().ToArray() |
.AsParallel() |
.Select(o => GetAttributeFromEnumValue<T>((Enum)o.GetValue(Activator.CreateInstance<T>()))); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Returns all the field names of an enumeration. |
/// </summary> |
/// <returns>the field names</returns> |
public static IEnumerable<string> GetEnumNames<T>() |
{ |
return |
typeof(T).GetRuntimeFields().ToArray() |
.AsParallel() |
.Select(o => o.GetCustomAttribute(typeof(NameAttribute), false)) |
.Select(o => (o as NameAttribute)?.Name) |
.Where(o => !string.IsNullOrEmpty(o)) |
.Select(o => o); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2014 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Returns all the values of an enumeration. |
/// </summary> |
/// <returns>the values of the enumeration</returns> |
public static IEnumerable<T> GetEnumValues<T>() |
{ |
return Enum.GetValues(typeof(T)).Cast<object>().Select(value => (T)value); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Get the name from an enumeration value. |
/// </summary> |
/// <param name="value">an enumeration value</param> |
/// <returns>the description or the empty string</returns> |
public static string GetNameFromEnumValue(Enum value) |
{ |
var attribute = value.GetType() |
.GetRuntimeField(value.ToString()) |
.GetCustomAttributes(typeof(NameAttribute), false) |
.SingleOrDefault() as NameAttribute; |
return attribute?.Name; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Get the description from an enumeration value. |
/// </summary> |
/// <param name="value">an enumeration value</param> |
/// <returns>the description or the empty string</returns> |
public static string GetDescriptionFromEnumValue(Enum value) |
{ |
var attribute = value.GetType() |
.GetRuntimeField(value.ToString()) |
.GetCustomAttributes(typeof(DescriptionAttribute), false) |
.SingleOrDefault() as DescriptionAttribute; |
return attribute?.Description; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Get enumeration value from its name attribute. |
/// </summary> |
/// <typeparam name="T">the enumeration type</typeparam> |
/// <param name="name">the description of a member</param> |
/// <param name="comparison">the string comparison to use</param> |
/// <returns>the value or the default of T if case no name attribute found</returns> |
public static T GetEnumValueFromName<T>(string name, |
StringComparison comparison = StringComparison.OrdinalIgnoreCase) |
{ |
var field = typeof(T).GetRuntimeFields().ToArray() |
.AsParallel().SelectMany(f => f.GetCustomAttributes( |
typeof(NameAttribute), false), ( |
f, a) => new { Field = f, Att = a }) |
.SingleOrDefault(a => string.Equals(((NameAttribute)a.Att) |
.Name, name, comparison)); |
return field != null ? (T)field.Field.GetValue(Activator.CreateInstance<T>()) : default(T); |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2015 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Get the name of a structure member. |
/// </summary> |
/// <typeparam name="T">the type of the structure to search</typeparam> |
/// <param name="structure">the structure to search</param> |
/// <param name="item">the value of the item to search</param> |
/// <returns>the description or the empty string</returns> |
public static string GetStructureMemberName<T>(T structure, object item) where T : struct |
{ |
var f = typeof(T).GetRuntimeFields(); |
var p = typeof(T).GetRuntimeProperties(); |
|
if (f != null) |
{ |
var r = f.AsParallel() |
.SelectMany(o => o.GetCustomAttributes(typeof(NameAttribute), false), |
(o, a) => new { Field = o, Att = a }) |
.SingleOrDefault(q => q.Field.GetValue(structure).Equals(item)); |
if (r != null) |
return ((NameAttribute)r.Att).Name; |
} |
|
if (p != null) |
{ |
var r = p.AsParallel() |
.SelectMany(o => o.GetCustomAttributes(typeof(NameAttribute), false), |
(o, a) => new { Property = o, Att = a }) |
.SingleOrDefault(q => q.Property.GetValue(structure).Equals(item)); |
if (r != null) |
return ((NameAttribute)r.Att).Name; |
} |
|
return string.Empty; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Get field or property from a class by supplying a path. |
/// </summary> |
/// <typeparam name="T">the type of the object</typeparam> |
/// <param name="o">the object</param> |
/// <param name="path">the fully qualified path to the field of property</param> |
/// <returns> |
/// the last object in the fully qualified path or null in case the field or property could not be found |
/// </returns> |
public static object GetFP<T>(this T o, string path) |
{ |
if (string.IsNullOrEmpty(path)) return null; |
if (o == null) return null; |
|
var memberType = o.GetType(); |
var components = path.Split('.'); |
|
var f = memberType.GetRuntimeField(components[0]); |
var p = memberType.GetRuntimeProperty(components[0]); |
|
if (f != null) |
return components.Length > 1 |
? GetFP(f.GetValue(o), |
components.Skip(1).Aggregate((a, i) => a + @"." + i)) |
: memberType.GetRuntimeField(path).GetValue(o); |
|
if (p != null) |
return components.Length > 1 |
? GetFP(p.GetValue(o), |
components.Skip(1).Aggregate((a, i) => a + @"." + i)) |
: memberType.GetRuntimeProperty(path).GetValue(o); |
|
return null; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Get field or property info from a class by supplying a path. |
/// </summary> |
/// <typeparam name="T">the type of the object</typeparam> |
/// <param name="o">the object</param> |
/// <param name="path">the fully qualified path to the field of property</param> |
/// <returns> |
/// the field or property info of the last object in the path or null if the object cannot be found |
/// </returns> |
public static object GetFPInfo<T>(this T o, string path) |
{ |
if (string.IsNullOrEmpty(path)) return null; |
if (o == null) return null; |
|
var memberType = o.GetType(); |
var components = path.Split('.'); |
|
var f = memberType.GetRuntimeField(components[0]); |
var p = memberType.GetRuntimeProperty(components[0]); |
|
if (f != null) |
return components.Length > 1 |
? GetFPInfo(f.GetValue(o), |
components.Skip(1).Aggregate((a, i) => a + @"." + i)) |
: memberType.GetRuntimeField(path); |
|
if (p != null) |
return components.Length > 1 |
? GetFPInfo(p.GetValue(o), |
components.Skip(1).Aggregate((a, i) => a + @"." + i)) |
: memberType.GetRuntimeProperty(path); |
|
return null; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary>Return all the run-time properties for an object.</summary> |
/// <param name="o">the object whose properties to return</param> |
/// <returns>the property information for all the properties of the object</returns> |
public static IEnumerable<PropertyInfo> GetPropertiesInfo<T>(this T o) |
{ |
foreach (var p in o.GetType().GetRuntimeProperties()) |
yield return p; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary>Return all the run-time properties for an object.</summary> |
/// <param name="o">the object whose properties to return</param> |
/// <returns>the property information for all the properties of the object</returns> |
public static IEnumerable<FieldInfo> GetFieldsInfo<T>(this T o) |
{ |
foreach (var p in o.GetType().GetRuntimeFields()) |
yield return p; |
} |
|
/////////////////////////////////////////////////////////////////////////// |
// Copyright (C) 2016 Wizardry and Steamworks - License: GNU GPLv3 // |
/////////////////////////////////////////////////////////////////////////// |
/// <summary> |
/// Enumerate all the base types recursively starting from a type. |
/// </summary> |
/// <param name="type">the type</param> |
/// <returns>an enumeration of all base types</returns> |
public static IEnumerable<Type> GetBaseTypes(this Type type) |
{ |
var baseType = type.GetTypeInfo().BaseType; |
if (baseType == null) |
yield break; |
yield return baseType; |
foreach (var t in GetBaseTypes(baseType)) |
{ |
yield return t; |
} |
} |
|
/// <summary> |
/// A generic name attribute. |
/// </summary> |
public class NameAttribute : Attribute |
{ |
protected readonly string name; |
|
public NameAttribute(string name) |
{ |
this.name = name; |
} |
|
public string Name => name; |
} |
|
/// <summary> |
/// A generic description attribute. |
/// </summary> |
public class DescriptionAttribute : Attribute |
{ |
protected readonly string description; |
|
public DescriptionAttribute(string description) |
{ |
this.description = description; |
} |
|
public string Description => description; |
} |
} |
} |
/wasSharp.csproj |
@@ -35,8 +35,6 @@ |
<AllowUnsafeBlocks>false</AllowUnsafeBlocks> |
</PropertyGroup> |
<ItemGroup> |
<Compile Include="Arrays.cs" /> |
<Compile Include="BitTwiddling.cs" /> |
<Compile Include="Collections\Generic\CircularQueue.cs" /> |
<Compile Include="Collections\Specialized\ConcurrentHashSet.cs" /> |
<Compile Include="Collections\Specialized\ConcurrentList.cs" /> |
@@ -48,20 +46,6 @@ |
<Compile Include="Collections\Generic\RangeCollection.cs" /> |
<Compile Include="Collections\Generic\SerializableDictionary.cs" /> |
<Compile Include="Collections\Generic\SerializableSortedDictionary.cs" /> |
<Compile Include="Cryptography.cs" /> |
<Compile Include="CSV.cs" /> |
<Compile Include="Extensions.cs" /> |
<Compile Include="Geodesics\Constants.cs" /> |
<Compile Include="Geodesics\Distance.cs" /> |
<Compile Include="Geodesics\GeodesicExtensions.cs" /> |
<Compile Include="Geodesics\GeographicCoordinate.cs" /> |
<Compile Include="NetHash.cs" /> |
<Compile Include="IO.cs" /> |
<Compile Include="KeyValue.cs" /> |
<Compile Include="Linq.cs" /> |
<Compile Include="Numerics.cs" /> |
<Compile Include="Reflection.cs" /> |
<Compile Include="Strings.cs" /> |
<Compile Include="Timers\DecayingAlarm.cs" /> |
<Compile Include="Timers\Utilities\TimeExtensions.cs" /> |
<Compile Include="Timers\TimedThrottle.cs" /> |
@@ -71,9 +55,36 @@ |
<Compile Include="Web\QValueParsing.cs" /> |
<Compile Include="Web\Utilities\WebExtensions.cs" /> |
<Compile Include="Web\wasHTTPClient.cs" /> |
<Compile Include="XML.cs" /> |
<Compile Include="Sciences\Geodesics\Constants.cs" /> |
<Compile Include="Sciences\Geodesics\Distance.cs" /> |
<Compile Include="Sciences\Geodesics\GeodesicExtensions.cs" /> |
<Compile Include="Sciences\Geodesics\GeographicCoordinate.cs" /> |
<Compile Include="Sciences\Mathematics\Numerics.cs" /> |
<Compile Include="IO\IO.cs" /> |
<Compile Include="Languages\CSV.cs" /> |
<Compile Include="Languages\KeyValue.cs" /> |
<Compile Include="Languages\XML.cs" /> |
<Compile Include="Bit\BitTwiddling.cs" /> |
<Compile Include="Cryptography\Cryptography.cs" /> |
<Compile Include="Arrays\Arrays.cs" /> |
<Compile Include="Lambda\Linq.cs" /> |
<Compile Include="Reflection\Reflection.cs" /> |
<Compile Include="Cryptography\NetHash.cs" /> |
<Compile Include="Cryptography\Extensions.cs" /> |
</ItemGroup> |
<ItemGroup /> |
<ItemGroup> |
<Folder Include="Sciences\" /> |
<Folder Include="Sciences\Geodesics\" /> |
<Folder Include="Sciences\Mathematics\" /> |
<Folder Include="IO\" /> |
<Folder Include="Languages\" /> |
<Folder Include="Bit\" /> |
<Folder Include="Cryptography\" /> |
<Folder Include="Arrays\" /> |
<Folder Include="Lambda\" /> |
<Folder Include="Reflection\" /> |
</ItemGroup> |
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" /> |
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. |
Other similar extension points exist, see Microsoft.Common.targets. |