Grunt.Js presentasjon kan lastes ned her:
http://www.aurstad.info/GruntJs.pdf [PDF]
using System; using System.IO; using System.IO.Compression; namespace TestCompression { ///In the code, memorystreams are used and the ToArray() method is used to generate byte arrays. The GZipStream can have a compression mode of either Compress or Decompress. The GZipStream in the compress and decompress methods are wrapped with BufferedStream with a buffer size of 64kB. This is done to be able to handle larger files. I have tested this code in a unit test with a lorem ipsum generated text file about 5,5 MB. The unit test is shown next:/// Compresses or decompresses byte arrays using GZipStream /// public static class ByteArrayCompressionUtility { private static int BUFFER_SIZE = 64*1024; //64kB public static byte[] Compress(byte[] inputData) { if (inputData == null) throw new ArgumentNullException("inputData must be non-null"); using (var compressIntoMs = new MemoryStream()) { using (var gzs = new BufferedStream(new GZipStream(compressIntoMs, CompressionMode.Compress), BUFFER_SIZE)) { gzs.Write(inputData, 0, inputData.Length); } return compressIntoMs.ToArray(); } } public static byte[] Decompress(byte[] inputData) { if (inputData == null) throw new ArgumentNullException("inputData must be non-null"); using (var compressedMs = new MemoryStream(inputData)) { using (var decompressedMs = new MemoryStream()) { using (var gzs = new BufferedStream(new GZipStream(compressedMs, CompressionMode.Decompress), BUFFER_SIZE)) { gzs.CopyTo(decompressedMs); } return decompressedMs.ToArray(); } } } //private static void Pump(Stream input, Stream output) //{ // byte[] bytes = new byte[4096]; // int n; // while ((n = input.Read(bytes, 0, bytes.Length)) != 0) // { // output.Write(bytes, 0, n); // } //} } }
using System; using NUnit.Framework; using System.Text; using System.IO; using System.Linq; namespace TestCompression.Test { [TestFixture] public class UnitTest1 { [Test] public void CompressAndUncompressString() { byte[] inputData = File.ReadAllBytes("Lorem1.txt"); byte[] compressedData = ByteArrayCompressionUtility.Compress(inputData); byte[] decompressedData = ByteArrayCompressionUtility.Decompress(compressedData); Assert.IsNotEmpty(inputData); Assert.IsNotEmpty(decompressedData); Assert.IsTrue(inputData.SequenceEqual(decompressedData)); Console.WriteLine("Compressed size: {0:F2}%", 100 * ((double)compressedData.Length / (double)decompressedData.Length)); //string outputString = Encoding.UTF8.GetString(decompressedData); } } }Output of this unit test is shown next:
------ Test started: Assembly: TestCompression.Test.dll ------ Compressed size: 28,74% 1 passed, 0 failed, 0 skipped, took 18,87 seconds (NUnit 2.6.2).To generate a lorem ipsum text file, you can use a lorep ipsum generator here: http://loripsum.net
public static class RandomGenerator { private static readonly RandomNumberGenerator generator; static RandomGenerator() { generator = RandomNumberGenerator.Create(); } public static int GetNext() { byte[] rndArray = new byte[4]; generator.GetBytes(rndArray); return BitConverter.ToInt32(rndArray, 0); } public static uint GetNextUnsigned() { byte[] rndArray = new byte[4]; generator.GetBytes(rndArray); return BitConverter.ToUInt32(rndArray, 0); } }The class is in fact a static class with a static RandomNumberGenerator instance created in the static constructor. The methods to create a new random number uses the GetBytes method to fill a four byte array. We could of course generate longer arrays and create for example 64-bits integers, but here just a four byte array is used. Either an integer or unsigned integer is returned by the two respective methods for this. I have not bothered to refactor this simple class. The BitConverter class converts the byte array to int or unsigned int (32-bits) starting at index 0. We could also return other datatypes here than just integers. Simple unit test:
[TestFixture] public class UnitTest1 { [Test] public void GetNextInteger() { int random = RandomGenerator.GetNext(); Debug.WriteLine(random); } [Test] public void GetNextUInteger() { uint random = RandomGenerator.GetNextUnsigned(); Debug.WriteLine(random); } }Sample output:
------ Test started: Assembly: TestRandomNumberGeneratorTest.dll ------ -1821995826 1013025195 2 passed, 0 failed, 0 skipped, took 0,42 seconds (NUnit 2.6.2).If you would like random numbers in a specified range, for example 0 to 99, you could take the integer and do a modulo 100 operation, e.g RandomGenerator.GetNextUnsigned() % 100. Of course, this is tied to the desired range you want. If a range between for example -20 and 20 is desired, you could for example do something like: -20 + (RandomGenerator.GetNextUnsigned() % 41). The bottom line is that you should not entrust the randomness of System.Random class but use the RandomNumberGenerator class in System.Security.Cryptography if you want to generate random integers, signed or unsigned that exhibit more distributed randomness than the pseudorandomness of System.Random.
$selected.Visual.DataContext.ModelCollection | Select OperationId, OperatingDate, OperationStatus | Format-Table -autosize OperationId OperatingDate OperationStatus ----------- ------------- --------------- 2076 Urgent 70 Urgent 2162 23.10.2013 00:00:00 Operation 2165 23.10.2013 00:00:00 Operation 2196 23.10.2013 00:00:00 Operation 2197 23.10.2013 00:00:00 Operation 0 23.10.2013 00:00:00 None 0 23.10.2013 00:00:00 None 0 23.10.2013 00:00:00 None 0 23.10.2013 00:00:00 None 0 23.10.2013 00:00:00 None 0 23.10.2013 00:00:00 None 0 23.10.2013 00:00:00 None 0 23.10.2013 00:00:00 None 0 23.10.2013 00:00:00 None 0 23.10.2013 00:00:00 None 0 23.10.2013 00:00:00 None 1913 Urgent 2192 23.10.2013 00:00:00 Operation 2193 23.10.2013 00:00:00 Operation 2194 23.10.2013 00:00:00 Operation 2013 23.10.2013 00:00:00 Operation 2195 23.10.2013 00:00:00 Operation 2161 23.10.2013 00:00:00 OperationIt could be possible to pipe this further to the Export-Csv Powershell cmdlet and you can have Excel launch the resulting .csv file. This shows how SnoopWpf can be used to do powerful runtime analysis and inspection of WPF applications and also support Powershell operators. Both technical testers and WPF developers will find this useful. To get started, install Snoop Wpf created by the brilliant developer Cory Plotts and can be downloaded from here: Snoop WPF
//using System; //using System.Collections.Generic; using System.Linq; using System.Threading; using System.Web; using System.Web.Script.Services; using System.Web.Services; namespace TestBootstrapCss { /// <summary> /// Summary description for CountryService /// </summary> [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] [System.ComponentModel.ToolboxItem(false)] [System.Web.Script.Services.ScriptService] public class CountryService : System.Web.Services.WebService { [WebMethod] [ScriptMethod(ResponseFormat = ResponseFormat.Json)] public Country[] GetCountries(string query) { if (cachedCountryList == null) cachedCountryList = GetCountryList(); var result = cachedCountryList.Where(c => c.Name.StartsWith(query, System.StringComparison.CurrentCultureIgnoreCase)).ToArray(); return result; } public class Country { public int Id { get; set; } public string Name { get; set; } public int Population { get; set; } public double WorldPercentage { get; set; } } private static Country[] cachedCountryList = null; public Country[] GetCountryList() { return new Country[] { new Country { Id =1,Name = "China",Population = 1354040000 ,WorldPercentage = 19.07 }, new Country { Id =2,Name = "India",Population = 1210569573 ,WorldPercentage = 17.05 }, new Country { Id =3,Name = "United States",Population = 316318000 ,WorldPercentage = 4.45 }, new Country { Id =4,Name = "Indonesia",Population = 237641326 ,WorldPercentage = 3.35 }, new Country { Id =5,Name = "Brazil",Population = 193946886 ,WorldPercentage = 2.73 }, new Country { Id =6,Name = "Pakistan",Population = 183766000 ,WorldPercentage = 2.59 }, new Country { Id =7,Name = "Nigeria",Population = 173615000 ,WorldPercentage = 2.45 }, new Country { Id =8,Name = "Bangladesh",Population = 152518015 ,WorldPercentage = 2.15 }, new Country { Id =9,Name = "Russia",Population = 143400000 ,WorldPercentage = 2.02 }, new Country { Id =10,Name = "Japan",Population = 127350000 ,WorldPercentage = 1.79 }, new Country { Id =11,Name = "Mexico",Population = 118419000 ,WorldPercentage = 1.67 }, new Country { Id =12,Name = "Philippines",Population = 98100000 ,WorldPercentage = 1.38 }, new Country { Id =13,Name = "Vietnam",Population = 88780000 ,WorldPercentage = 1.25 }, new Country { Id =14,Name = "Ethiopia",Population = 86613986 ,WorldPercentage = 1.22 }, new Country { Id =15,Name = "Egypt",Population = 83661000 ,WorldPercentage = 1.18 }, new Country { Id =16,Name = "Germany",Population = 80493000 ,WorldPercentage = 1.13 }, new Country { Id =17,Name = "Iran",Population = 76768000 ,WorldPercentage = 1.08 }, new Country { Id =18,Name = "Turkey",Population = 75627384 ,WorldPercentage = 1.07 }, new Country { Id =19,Name = "Democratic Republic of the Congo",Population = 67514000 ,WorldPercentage = 0.95 }, new Country { Id =20,Name = "Thailand",Population = 65926261 ,WorldPercentage = 0.93 }, new Country { Id =21,Name = "France[9]",Population = 65684000 ,WorldPercentage = 0.92 }, new Country { Id =22,Name = "United Kingdom",Population = 63181775 ,WorldPercentage = 0.89 }, new Country { Id =23,Name = "Italy",Population = 59704082 ,WorldPercentage = 0.84 }, new Country { Id =24,Name = "Myanmar",Population = 53259000 ,WorldPercentage = 0.75 }, new Country { Id =25,Name = "South Africa",Population = 52981991 ,WorldPercentage = 0.75 }, new Country { Id =26,Name = "South Korea",Population = 50219669 ,WorldPercentage = 0.71 }, new Country { Id =27,Name = "Colombia",Population = 47159000 ,WorldPercentage = 0.66 }, new Country { Id =28,Name = "Spain",Population = 47059533 ,WorldPercentage = 0.66 }, new Country { Id =29,Name = "Ukraine",Population = 45495252 ,WorldPercentage = 0.64 }, new Country { Id =30,Name = "Tanzania",Population = 44928923 ,WorldPercentage = 0.63 }, new Country { Id =31,Name = "Kenya",Population = 44354000 ,WorldPercentage = 0.62 }, new Country { Id =32,Name = "Argentina",Population = 40117096 ,WorldPercentage = 0.57 }, new Country { Id =33,Name = "Poland",Population = 38533299 ,WorldPercentage = 0.54 }, new Country { Id =34,Name = "Sudan",Population = 37964000 ,WorldPercentage = 0.53 }, new Country { Id =35,Name = "Algeria",Population = 37900000 ,WorldPercentage = 0.53 }, new Country { Id =36,Name = "Canada",Population = 35141542 ,WorldPercentage = 0.49 }, new Country { Id =37,Name = "Uganda",Population = 34131400 ,WorldPercentage = 0.48 }, new Country { Id =38,Name = "Iraq",Population = 33330000 ,WorldPercentage = 0.47 }, new Country { Id =39,Name = "Morocco",Population = 32973200 ,WorldPercentage = 0.46 }, new Country { Id =40,Name = "Peru",Population = 30475144 ,WorldPercentage = 0.43 }, new Country { Id =41,Name = "Malaysia",Population = 29747000 ,WorldPercentage = 0.42 }, new Country { Id =42,Name = "Uzbekistan",Population = 29559100 ,WorldPercentage = 0.42 }, new Country { Id =43,Name = "Saudi Arabia",Population = 29195895 ,WorldPercentage = 0.41 }, new Country { Id =44,Name = "Venezuela",Population = 28946101 ,WorldPercentage = 0.41 }, new Country { Id =45,Name = "Nepal",Population = 26494504 ,WorldPercentage = 0.37 }, new Country { Id =46,Name = "Afghanistan",Population = 25500100 ,WorldPercentage = 0.36 }, new Country { Id =47,Name = "North Korea",Population = 24895000 ,WorldPercentage = 0.35 }, new Country { Id =48,Name = "Ghana",Population = 24658823 ,WorldPercentage = 0.35 }, new Country { Id =49,Name = "Yemen",Population = 24527000 ,WorldPercentage = 0.35 }, new Country { Id =50,Name = "Mozambique",Population = 24366112 ,WorldPercentage = 0.34 }, new Country { Id =51,Name = "Taiwan[10]",Population = 23340136 ,WorldPercentage = 0.33 }, new Country { Id =52,Name = "Ivory Coast",Population = 23202000 ,WorldPercentage = 0.33 }, new Country { Id =53,Name = "Australia",Population = 23096296 ,WorldPercentage = 0.33 }, new Country { Id =54,Name = "Syria",Population = 21377000 ,WorldPercentage = 0.3 }, new Country { Id =55,Name = "Madagascar",Population = 20696070 ,WorldPercentage = 0.29 }, new Country { Id =56,Name = "Angola",Population = 20609294 ,WorldPercentage = 0.29 }, new Country { Id =57,Name = "Cameroon",Population = 20386799 ,WorldPercentage = 0.29 }, new Country { Id =58,Name = "Sri Lanka",Population = 20277597 ,WorldPercentage = 0.29 }, new Country { Id =59,Name = "Romania",Population = 20121641 ,WorldPercentage = 0.28 }, new Country { Id =60,Name = "Burkina Faso",Population = 17322796 ,WorldPercentage = 0.24 }, new Country { Id =61,Name = "Niger",Population = 17129076 ,WorldPercentage = 0.24 }, new Country { Id =62,Name = "Kazakhstan",Population = 17010000 ,WorldPercentage = 0.24 }, new Country { Id =63,Name = "Netherlands",Population = 16793700 ,WorldPercentage = 0.24 }, new Country { Id =64,Name = "Chile",Population = 16634603 ,WorldPercentage = 0.23 }, new Country { Id =65,Name = "Ecuador",Population = 15535800 ,WorldPercentage = 0.22 }, new Country { Id =66,Name = "Guatemala",Population = 15438384 ,WorldPercentage = 0.22 }, new Country { Id =67,Name = "Mali",Population = 15302000 ,WorldPercentage = 0.22 }, new Country { Id =68,Name = "Cambodia",Population = 15135000 ,WorldPercentage = 0.21 }, new Country { Id =69,Name = "Malawi",Population = 14388600 ,WorldPercentage = 0.2 }, new Country { Id =70,Name = "Senegal",Population = 13567338 ,WorldPercentage = 0.19 }, new Country { Id =71,Name = "Zambia",Population = 13092666 ,WorldPercentage = 0.18 }, new Country { Id =72,Name = "Zimbabwe",Population = 12973808 ,WorldPercentage = 0.18 }, new Country { Id =73,Name = "Chad",Population = 12825000 ,WorldPercentage = 0.18 }, new Country { Id =74,Name = "South Sudan",Population = 11296000 ,WorldPercentage = 0.16 }, new Country { Id =75,Name = "Cuba",Population = 11163934 ,WorldPercentage = 0.16 }, new Country { Id =76,Name = "Belgium",Population = 11156136 ,WorldPercentage = 0.16 }, new Country { Id =77,Name = "Guinea",Population = 10824200 ,WorldPercentage = 0.15 }, new Country { Id =78,Name = "Greece",Population = 10815197 ,WorldPercentage = 0.15 }, new Country { Id =79,Name = "Tunisia",Population = 10777500 ,WorldPercentage = 0.15 }, new Country { Id =80,Name = "Portugal",Population = 10562178 ,WorldPercentage = 0.15 }, new Country { Id =81,Name = "Rwanda",Population = 10537222 ,WorldPercentage = 0.15 }, new Country { Id =82,Name = "Czech Republic",Population = 10512800 ,WorldPercentage = 0.15 }, new Country { Id =83,Name = "Somalia[11]",Population = 10496000 ,WorldPercentage = 0.15 }, new Country { Id =84,Name = "Haiti",Population = 10413211 ,WorldPercentage = 0.15 }, new Country { Id =85,Name = "Bolivia",Population = 10389913 ,WorldPercentage = 0.15 }, new Country { Id =86,Name = "Benin",Population = 10323000 ,WorldPercentage = 0.15 }, new Country { Id =87,Name = "Burundi",Population = 10163000 ,WorldPercentage = 0.14 }, new Country { Id =88,Name = "Hungary",Population = 9906000 ,WorldPercentage = 0.14 }, new Country { Id =89,Name = "Sweden",Population = 9588569 ,WorldPercentage = 0.14 }, new Country { Id =90,Name = "Belarus",Population = 9458700 ,WorldPercentage = 0.13 }, new Country { Id =91,Name = "Dominican Republic",Population = 9445281 ,WorldPercentage = 0.13 }, new Country { Id =92,Name = "Azerbaijan",Population = 9235100 ,WorldPercentage = 0.13 }, new Country { Id =93,Name = "Austria",Population = 8464554 ,WorldPercentage = 0.12 }, new Country { Id =94,Name = "Honduras",Population = 8385072 ,WorldPercentage = 0.12 }, new Country { Id =95,Name = "United Arab Emirates",Population = 8264070 ,WorldPercentage = 0.12 }, new Country { Id =96,Name = "Switzerland",Population = 8058100 ,WorldPercentage = 0.11 }, new Country { Id =97,Name = "Israel",Population = 8034900 ,WorldPercentage = 0.11 }, new Country { Id =98,Name = "Tajikistan",Population = 8000000 ,WorldPercentage = 0.11 }, new Country { Id =99,Name = "Bulgaria",Population = 7282041 ,WorldPercentage = 0.1 }, new Country { Id =100,Name = "Serbia[12]",Population = 7241295 ,WorldPercentage = 0.1 }, new Country { Id =101,Name = "Hong Kong (China)",Population = 7173900 ,WorldPercentage = 0.1 }, new Country { Id =102,Name = "Papua New Guinea",Population = 7059653 ,WorldPercentage = 0.099 }, new Country { Id =103,Name = "Paraguay",Population = 6672631 ,WorldPercentage = 0.094 }, new Country { Id =104,Name = "Laos",Population = 6580800 ,WorldPercentage = 0.093 }, new Country { Id =105,Name = "Jordan",Population = 6467500 ,WorldPercentage = 0.09 }, new Country { Id =106,Name = "Eritrea",Population = 6333000 ,WorldPercentage = 0.089 }, new Country { Id =107,Name = "Libya",Population = 6202000 ,WorldPercentage = 0.087 }, new Country { Id =108,Name = "Togo",Population = 6191155 ,WorldPercentage = 0.087 }, new Country { Id =109,Name = "El Salvador",Population = 6183000 ,WorldPercentage = 0.087 }, new Country { Id =110,Name = "Sierra Leone",Population = 6092000 ,WorldPercentage = 0.086 }, new Country { Id =111,Name = "Nicaragua",Population = 6071045 ,WorldPercentage = 0.086 }, new Country { Id =112,Name = "Denmark",Population = 5605836 ,WorldPercentage = 0.079 }, new Country { Id =113,Name = "Kyrgyzstan",Population = 5551900 ,WorldPercentage = 0.078 }, new Country { Id =114,Name = "Finland",Population = 5434357 ,WorldPercentage = 0.077 }, new Country { Id =115,Name = "Slovakia",Population = 5410728 ,WorldPercentage = 0.076 }, new Country { Id =116,Name = "Singapore",Population = 5312400 ,WorldPercentage = 0.075 }, new Country { Id =117,Name = "Turkmenistan",Population = 5240000 ,WorldPercentage = 0.074 }, new Country { Id =118,Name = "Norway",Population = 5063709 ,WorldPercentage = 0.071 }, new Country { Id =119,Name = "Lebanon",Population = 4822000 ,WorldPercentage = 0.068 }, new Country { Id =120,Name = "Costa Rica",Population = 4667096 ,WorldPercentage = 0.066 }, new Country { Id =121,Name = "Central African Republic",Population = 4616000 ,WorldPercentage = 0.065 }, new Country { Id =122,Name = "Ireland",Population = 4585400 ,WorldPercentage = 0.065 }, new Country { Id =123,Name = "Georgia[13]",Population = 4483800 ,WorldPercentage = 0.063 }, new Country { Id =124,Name = "New Zealand",Population = 4471380 ,WorldPercentage = 0.063 }, new Country { Id =125,Name = "Republic of the Congo",Population = 4448000 ,WorldPercentage = 0.063 }, new Country { Id =126,Name = "Palestine[14]",Population = 4420549 ,WorldPercentage = 0.062 }, new Country { Id =127,Name = "Liberia",Population = 4294000 ,WorldPercentage = 0.06 }, new Country { Id =128,Name = "Croatia",Population = 4290612 ,WorldPercentage = 0.06 }, new Country { Id =129,Name = "Bosnia and Herzegovina",Population = 3839737 ,WorldPercentage = 0.054 }, new Country { Id =130,Name = "Oman",Population = 3831553 ,WorldPercentage = 0.054 }, new Country { Id =131,Name = "Puerto Rico (USA)",Population = 3667084 ,WorldPercentage = 0.052 }, new Country { Id =132,Name = "Kuwait",Population = 3582054 ,WorldPercentage = 0.05 }, new Country { Id =133,Name = "Moldova[15]",Population = 3559500 ,WorldPercentage = 0.05 }, new Country { Id =134,Name = "Mauritania",Population = 3461041 ,WorldPercentage = 0.049 }, new Country { Id =135,Name = "Panama",Population = 3405813 ,WorldPercentage = 0.048 }, new Country { Id =136,Name = "Uruguay",Population = 3286314 ,WorldPercentage = 0.046 }, new Country { Id =137,Name = "Armenia",Population = 3031200 ,WorldPercentage = 0.043 }, new Country { Id =138,Name = "Lithuania",Population = 2960733 ,WorldPercentage = 0.042 }, new Country { Id =139,Name = "Albania",Population = 2821977 ,WorldPercentage = 0.04 }, new Country { Id =140,Name = "Mongolia",Population = 2754685 ,WorldPercentage = 0.039 }, new Country { Id =141,Name = "Jamaica",Population = 2711476 ,WorldPercentage = 0.038 }, new Country { Id =142,Name = "Namibia",Population = 2113077 ,WorldPercentage = 0.03 }, new Country { Id =143,Name = "Lesotho",Population = 2074000 ,WorldPercentage = 0.029 }, new Country { Id =144,Name = "Slovenia",Population = 2060461 ,WorldPercentage = 0.029 }, new Country { Id =145,Name = "Macedonia",Population = 2059794 ,WorldPercentage = 0.029 }, new Country { Id =146,Name = "Botswana",Population = 2024904 ,WorldPercentage = 0.029 }, new Country { Id =147,Name = "Latvia",Population = 2013400 ,WorldPercentage = 0.028 }, new Country { Id =148,Name = "Qatar",Population = 1963124 ,WorldPercentage = 0.028 }, new Country { Id =149,Name = "Gambia",Population = 1849000 ,WorldPercentage = 0.026 }, new Country { Id =150,Name = "Guinea-Bissau",Population = 1704000 ,WorldPercentage = 0.024 }, new Country { Id =151,Name = "Gabon",Population = 1672000 ,WorldPercentage = 0.024 }, new Country { Id =152,Name = "Equatorial Guinea",Population = 1622000 ,WorldPercentage = 0.023 }, new Country { Id =153,Name = "Trinidad and Tobago",Population = 1328019 ,WorldPercentage = 0.019 }, new Country { Id =154,Name = "Estonia",Population = 1286540 ,WorldPercentage = 0.018 }, new Country { Id =155,Name = "Mauritius",Population = 1257900 ,WorldPercentage = 0.018 }, new Country { Id =156,Name = "Swaziland",Population = 1250000 ,WorldPercentage = 0.018 }, new Country { Id =157,Name = "Bahrain",Population = 1234571 ,WorldPercentage = 0.017 }, new Country { Id =158,Name = "Timor-Leste",Population = 1066409 ,WorldPercentage = 0.015 }, new Country { Id =159,Name = "Djibouti",Population = 864618 ,WorldPercentage = 0.012 }, new Country { Id =160,Name = "Cyprus[16]",Population = 862 ,WorldPercentage = 0.012 }, new Country { Id =161,Name = "Fiji",Population = 858038 ,WorldPercentage = 0.012 }, new Country { Id =162,Name = "Réunion (France)",Population = 821136 ,WorldPercentage = 0.012 }, new Country { Id =163,Name = "Guyana",Population = 784894 ,WorldPercentage = 0.011 }, new Country { Id =164,Name = "Bhutan",Population = 73674 ,WorldPercentage = 0.01 }, new Country { Id =165,Name = "Comoros",Population = 7243 ,WorldPercentage = 0.01 }, new Country { Id =166,Name = "Montenegro",Population = 620029 ,WorldPercentage = 0.0087 }, new Country { Id =167,Name = "Macau (China)",Population = 582 ,WorldPercentage = 0.0082 }, new Country { Id =168,Name = "Western Sahara[17]",Population = 567 ,WorldPercentage = 0.008 }, new Country { Id =169,Name = "Solomon Islands",Population = 561 ,WorldPercentage = 0.0079 }, new Country { Id =170,Name = "Luxembourg",Population = 537 ,WorldPercentage = 0.0076 }, new Country { Id =171,Name = "Suri,Name",Population = 534189 ,WorldPercentage = 0.0075 }, new Country { Id =172,Name = "Cape Verde",Population = 491875 ,WorldPercentage = 0.0069 }, new Country { Id =173,Name = "Malta",Population = 416055 ,WorldPercentage = 0.0059 }, new Country { Id =174,Name = "Guadeloupe (France)",Population = 403355 ,WorldPercentage = 0.0057 }, new Country { Id =175,Name = "Martinique (France)",Population = 394173 ,WorldPercentage = 0.0056 }, new Country { Id =176,Name = "Brunei",Population = 393162 ,WorldPercentage = 0.0055 }, new Country { Id =177,Name = "Bahamas",Population = 351461 ,WorldPercentage = 0.0049 }, new Country { Id =178,Name = "Iceland",Population = 32381 ,WorldPercentage = 0.0045 }, new Country { Id =179,Name = "Maldives",Population = 31728 ,WorldPercentage = 0.0045 }, new Country { Id =180,Name = "Belize",Population = 312971 ,WorldPercentage = 0.0044 }, new Country { Id =181,Name = "Barbados",Population = 2742 ,WorldPercentage = 0.0039 }, new Country { Id =182,Name = "French Polynesia (France)",Population = 26827 ,WorldPercentage = 0.0038 }, new Country { Id =183,Name = "Vanuatu",Population = 258213 ,WorldPercentage = 0.0036 }, new Country { Id =184,Name = "New Caledonia (France)",Population = 255651 ,WorldPercentage = 0.0036 }, new Country { Id =185,Name = "French Guiana (France)",Population = 22904 ,WorldPercentage = 0.0032 }, new Country { Id =186,Name = "Mayotte (France)",Population = 2126 ,WorldPercentage = 0.003 }, new Country { Id =187,Name = "Samoa",Population = 18782 ,WorldPercentage = 0.0026 }, new Country { Id =188,Name = "São Tomé and Príncipe",Population = 187356 ,WorldPercentage = 0.0026 }, new Country { Id =189,Name = "Saint Lucia",Population = 166526 ,WorldPercentage = 0.0023 }, new Country { Id =190,Name = "Guam (USA)",Population = 159358 ,WorldPercentage = 0.0022 }, new Country { Id =191,Name = "Curaçao (Netherlands)",Population = 150563 ,WorldPercentage = 0.0021 }, new Country { Id =192,Name = "Saint Vincent and the Grenadines",Population = 109 ,WorldPercentage = 0.0015 }, new Country { Id =193,Name = "United States Virgin Islands (USA)",Population = 106405 ,WorldPercentage = 0.0015 }, new Country { Id =194,Name = "Kiribati",Population = 104573 ,WorldPercentage = 0.0015 }, new Country { Id =195,Name = "Grenada",Population = 103328 ,WorldPercentage = 0.0015 }, new Country { Id =196,Name = "Tonga",Population = 103036 ,WorldPercentage = 0.0015 }, new Country { Id =197,Name = "Federated States of Micronesia",Population = 101823 ,WorldPercentage = 0.0014 }, new Country { Id =198,Name = "Aruba (Netherlands)",Population = 101484 ,WorldPercentage = 0.0014 }, new Country { Id =199,Name = "Jersey (UK)",Population = 97857 ,WorldPercentage = 0.0014 }, new Country { Id =200,Name = "Seychelles",Population = 90945 ,WorldPercentage = 0.0013 }, new Country { Id =201,Name = "Antigua and Barbuda",Population = 86295 ,WorldPercentage = 0.0012 }, new Country { Id =202,Name = "Isle of Man (UK)",Population = 84497 ,WorldPercentage = 0.0012 }, new Country { Id =203,Name = "Andorra",Population = 76246 ,WorldPercentage = 0.0011 }, new Country { Id =204,Name = "Dominica",Population = 71293 ,WorldPercentage = 0.001 }, new Country { Id =205,Name = "Bermuda (UK)",Population = 64237 ,WorldPercentage = 0.0009 }, new Country { Id =206,Name = "Guernsey (UK)",Population = 62431 ,WorldPercentage = 0.00088 }, new Country { Id =207,Name = "Greenland (Denmark)",Population = 5637 ,WorldPercentage = 0.00079 }, new Country { Id =208,Name = "Marshall Islands",Population = 55548 ,WorldPercentage = 0.00078 }, new Country { Id =209,Name = "American Samoa (USA)",Population = 55519 ,WorldPercentage = 0.00078 }, new Country { Id =210,Name = "Cayman Islands (UK)",Population = 55456 ,WorldPercentage = 0.00078 }, new Country { Id =211,Name = "Saint Kitts and Nevis",Population = 54 ,WorldPercentage = 0.00076 }, new Country { Id =212,Name = "Northern Mariana Islands (USA)",Population = 53883 ,WorldPercentage = 0.00076 }, new Country { Id =213,Name = "Faroe Islands (Denmark)",Population = 48244 ,WorldPercentage = 0.00068 }, new Country { Id =214,Name = "Sint Maarten (Netherlands)",Population = 37429 ,WorldPercentage = 0.00053 }, new Country { Id =215,Name = "Saint Martin (France)",Population = 36979 ,WorldPercentage = 0.00052 }, new Country { Id =216,Name = "Liechtenstein",Population = 36842 ,WorldPercentage = 0.00052 }, new Country { Id =217,Name = "Monaco",Population = 36136 ,WorldPercentage = 0.00051 }, new Country { Id =218,Name = "San Marino",Population = 32382 ,WorldPercentage = 0.00046 }, new Country { Id =219,Name = "Turks and Caicos Islands (UK)",Population = 31458 ,WorldPercentage = 0.00044 }, new Country { Id =220,Name = "Gibraltar (UK)",Population = 29752 ,WorldPercentage = 0.00042 }, new Country { Id =221,Name = "British Virgin Islands (UK)",Population = 29537 ,WorldPercentage = 0.00042 }, new Country { Id =222,Name = "Åland Islands (Finland)",Population = 28502 ,WorldPercentage = 0.0004 }, new Country { Id =223,Name = "Caribbean Netherlands (Netherlands)",Population = 21133 ,WorldPercentage = 0.0003 }, new Country { Id =224,Name = "Palau",Population = 2077 ,WorldPercentage = 0.00029 }, new Country { Id =225,Name = "Cook Islands (NZ)",Population = 14974 ,WorldPercentage = 0.00021 }, new Country { Id =226,Name = "Anguilla (UK)",Population = 13452 ,WorldPercentage = 0.00019 }, new Country { Id =227,Name = "Wallis and Futuna (France)",Population = 13152 ,WorldPercentage = 0.00019 }, new Country { Id =228,Name = "Tuvalu",Population = 11264 ,WorldPercentage = 0.00016 }, new Country { Id =229,Name = "Nauru",Population = 9945 ,WorldPercentage = 0.00014 }, new Country { Id =230,Name = "Saint Barthélemy (France)",Population = 8938 ,WorldPercentage = 0.00013 }, new Country { Id =231,Name = "Saint Pierre and Miquelon (France)",Population = 6081 ,WorldPercentage = 0.00006 }, new Country { Id =232,Name = "Montserrat (UK)",Population = 4922 ,WorldPercentage = 0.00005 }, new Country { Id =233,Name = "Saint Helena Ascension and Tristan da Cunha (UK)",Population = 4 ,WorldPercentage = 0.00004 }, new Country { Id =234,Name = "Svalbard and Jan Mayen (Norway)",Population = 2655 ,WorldPercentage = 0.00003 }, new Country { Id =235,Name = "Falkland Islands (UK)",Population = 2563 ,WorldPercentage = 0.00003 }, new Country { Id =236,Name = "Norfolk Island (Australia)",Population = 2302 ,WorldPercentage = 0.00002 }, new Country { Id =237,Name = "Christmas Island (Australia)",Population = 2072 ,WorldPercentage = 0.00002 }, new Country { Id =238,Name = "Niue (NZ)",Population = 1613 ,WorldPercentage = 0.00002 }, new Country { Id =239,Name = "Tokelau (NZ)",Population = 1411 ,WorldPercentage = 0.00001 }, new Country { Id =240,Name = " Vatican City",Population = 800 ,WorldPercentage = 0.00001 }, new Country { Id =241,Name = "Cocos (Keeling) Islands (Australia)",Population = 550 ,WorldPercentage = 0.000001 }, new Country { Id =242,Name = "Pitcairn Islands (UK)",Population = 66 ,WorldPercentage = 0.0000000 } }; } } }As you can see, we must tag the service with the ScriptService and tag the WebMethod with the ScriptMethod attribute, specifying the JSON responseformat. We also need to add some to our web.config:
<?xml version="1.0"?> <!-- For more information on how to configure your ASP.NET application, please visit http://go.microsoft.com/fwlink/?LinkId=169433 --> <configuration> <system.web> <compilation debug="true" targetFramework="4.5" /> <httpRuntime targetFramework="4.5" /> <webServices> <protocols> <add name="HttpGet" /> <add name="HttpPost"/> </protocols> </webServices> </system.web> </configuration>We also need some GUI here to test out the TypeAhead control:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head< <title></title> <link href="Content/bootstrap.css" rel="stylesheet" /> <link href="Content/bootstrap-responsive.css" rel="stylesheet" /> </head> <body> <div class="row"> <div class="span12"> <input type="text" id="tbCountries" /> </div class="row"> <script src="Scripts/jquery-2.0.3.js"></script> <script src="Scripts/bootstrap.js"></script> <script src="Scripts/underscore.js"></script> <script type="text/javascript"> $(function () { var countries; $("#tbCountries").typeahead({ source: function (query, process) { return $.ajax({ type: "POST", url: 'http://localhost:52523/CountryService.asmx/GetCountries', data: JSON.stringify({query: query }), contentType: "application/json; charset=utf-8", dataType: "json", success: function (data) { countries = data.d; var countryIds = _.map(countries, function(c){ return c.Id; }); return process(countryIds); } }); }, matcher: function (item) { return true; }, sorter: function (items) { return items; }, highlighter: function (id) { var country = _.find(countries, function (c) { return c.Id == id; }); return country.Name + " Population: " + country.Population; }, updater: function (id) { var country = _.find(countries, function (c) { return c.Id == id; }); return country.Name; } }); }); </script> </body> </html>To sum up, to make the TypeAhead control work in my example, I had to implement stub implementations of matcher, sorter, highlighter (must be implemented such that the custom Country object instances return in JSON object is visible, this is a display template in other words) and updater (will update the text field with the autocomplete / TypeAhead feature). Source also sets a global variable countries here for simplicity, and continues processing the ids, you can see that we use Underscore.Js here for the array processing. The highlighter and updater method uses the find method of Underscore.js to find the relevant country. The end result is a functioning auto complete example for the Bootstrap TypeAhead control that uses a remote JSON service. I am not sure why the data.d variable was returned from the service. I did not specify "data.d" anywhere in my code, but this is where I could find the returned JSON data. It is not very elegant to set the countries to a global variable, we could of course encapsulate this better using a "provider" to encapsulate the data for encapsulation and consistency protection. But the key point of this article was to help others getting started with the TypeAhead control in Bootstrap with remote JSON calls returning objects with properties and not just simple string arrays. I find the Bootstrap documentation from Twitter as good, but not exemplary. It is sometimes hard to find good programming examples on the different controls. The end result is an autocomplete control that looks nice and can display compound data:
var AppUtils = AppUtils || {}; AppUtils.LocalStorageUtility = function(storageKeys, sourceElements, feedbackElement) { this.storageKeys = storageKeys; this.sourceElements = sourceElements; this.feedbackElement = feedbackElement; }; AppUtils.LocalStorageUtility.prototype = (function () { var storeSettings = function (thisObj) { for (var i = 0; i < thisObj.storageKeys.length; i++) { var storageKey = thisObj.storageKeys[i]; var elementName = thisObj.sourceElements[i]; localStorage.setItem(storageKey, $("#" + elementName).val()); } $("#" + thisObj.feedbackElement).text("Local setting saved!"); }, loadSettings = function (thisObj) { for (var i = 0; i < thisObj.storageKeys.length; i++) { var storageKey = thisObj.storageKeys[i]; var elementName = thisObj.sourceElements[i]; $("#" + elementName).val(localStorage.getItem(storageKey)); } $("#" + thisObj.feedbackElement).text("Local setting loaded!"); }, clearSettings = function () { localStorage.clear(); }, hasLocalStorage = function () { return typeof (Storage) !== "undefined"; } return { StoreSettings: storeSettings, LoadSettings: loadSettings, ClearSettings: clearSettings, HasLocalStorage: hasLocalStorage }; })();The consumer of this class-like structure in Javascript will provide two string arrays which is the local storage key names and the elements to read and store local storage values from. I do not do any checking here that the two arrays are the same length or that they are of the correct type (arrays preferably with string of course). This is what TypeScript version of this code would specify. Remember, TypeScript is much easier to use than manually creating class like structs like we do here, but the concepts are anyways important to understand. In the revealing prototype pattern we return an object literal and the public part is exposed here, i.e. the revealing prototype. In addition, we call it revealing because the prototype is self invoking. The private parts are what is outside of the return statement above. We point to the private methods, and this is fine, and we alias them to a capitalized version to let the user call into the private methods. If we want public fields We also need a GUI for the Javascript code here:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Localstorage demo</title> </head> <script src="Scripts/jquery-2.0.3.min.js"></script> <script src="Scripts/LocalStorageUtility.js"></script> <script type="text/javascript"> $(document).ready(function () { var ls = new AppUtils.LocalStorageUtility(["Name", "City"], ["tbName", "tbCity"], "lblFeedback"); if (ls.HasLocalStorage) { $("#lblFeedback").text("Local storage is enabled!"); } else { $("#lblFeedback").text("Local storage is disabled!"); } $("#btnLoadSettings").click(function () { ls.LoadSettings(ls); }); $("#btnSaveSettings").click(function () { ls.StoreSettings(ls); }); $("#btnClearSettings").click(ls.ClearSettings); }); </script> <body> <table> <tr> <td>Name</td><td><input id="tbName" type="text" /></td> <td>City</td><td><input id="tbCity" type="text" /></td> </tr> </table> <button id="btnLoadSettings" type="button">Load settings</button> <button id="btnSaveSettings" type="button">Save settings</button> <button id="btnClearSettings" type="button">Clear settings</button> <p id="lblFeedback" style="color: darkgreen">ready</p> </body> </html>As you can see, with this pattern we must keep track of the this pointer in the prototype definition. There are alternatives, such as bind, and call, but I wanted to keep the example clear. In the jQuery load method above we define click handlers that pass in the instance of the LocalStorageUtility, which we have instantiated, such that the prototype gets the correct instance. As you perhaps know, the prototype must bind to the correct this pointer, and here we explicitly pass it in (i.e. the instance of LocalStorageUtility). Finally, note that we define a namespace here with the "or empty object literal" technique. This allows us to hide the entire class from the global namespace and improve or encapsulation even more. If you have comments to the code above, please let me know. I have worked some with Javascript of course, but I am still learning a lot about it.