Wednesday, February 13, 2013

The Law of Averages

The Law of Averages is not actually a law, but really just a lay term for some mathematical principles either completely unfounded in any mathematical law or borrowed from the Law of Large Numbers.  For more information, see this Wikipedia article.  However, this post is titled 'The Law of Averages' because I wanted to go into some detail about averaging averages.

In particular, I was asked this question: "If I have a data point for every minute of the data, I also have an average of 15 data points for every 15 minute period of the day, and I wanted to calculate the daily average, it would be better to use the 1 minute data versus the 15 minute averages (aka rollup data).  The average of the 15 minute averages would really be an average of averages and is therefore not accurate."

The reality is actually contrary to that thinking.  The average of averages of data is exactly the same as the average of the same source data.  To illustrate this, let's look at some data.

Below, we have random numbers between 0 and 100 to represent our data.  We have one data point for each minute of the day.  Every 15 minutes, an average is calculated.  For example, at 0:30 an average is calculated averaging the points from 0:30-0:44.

Time1 Minute Data15 Minute Average
0:003751.6666666666667
0:0174
0:0249
0:0321
0:0459
0:0515
0:0632
0:0769
0:0840
0:0926
0:1087
0:1138
0:1296
0:1379
0:1453
0:156025.8
0:1635
0:177
0:1824
0:1946
0:203
0:2122
0:221
0:2339
0:249
0:2534
0:260
0:2742
0:2834
0:2931
0:30433.8
0:315
0:3281
0:3336
0:3435
0:359
0:3636
0:3741
0:3876
0:3993
0:4021
0:4112
0:4210
0:4321
0:4427
0:45548.8
0:4642
0:4783
0:4848
0:4918
0:5079
0:5124
0:5278
0:5319
0:545
0:5552
0:56100
0:5739
0:5870
0:5970
1:001444.0666666666667
1:0145
1:0282
1:0334
1:0474
1:0590
1:0633
1:0710
1:0843
1:0924
1:1096
1:1112
1:1217
1:1362
1:1425
1:159654.7333333333333
1:1619
1:1791
1:1858
1:1976
1:2024
1:2186
1:2235
1:2348
1:2431
1:2567
1:2672
1:279
1:2845
1:2964
1:307940.4
1:3168
1:320
1:3310
1:3430
1:3523
1:3665
1:3774
1:3853
1:3978
1:404
1:413
1:4238
1:4378
1:443
1:459147.6
1:4685
1:4744
1:484
1:496
1:5013
1:5139
1:5293
1:5352
1:5435
1:5549
1:5669
1:5767
1:5864
1:593
2:001156.8666666666667
2:0172
2:0254
2:0345
2:0416
2:0517
2:0675
2:0796
2:0896
2:0962
2:1080
2:1155
2:1296
2:1334
2:1444
2:157346.6666666666667
2:1657
2:1721
2:1861
2:1928
2:2011
2:2116
2:221
2:2386
2:2423
2:2564
2:2689
2:2746
2:2838
2:2986
2:304245.8
2:3115
2:327
2:333
2:3440
2:3541
2:368
2:3766
2:381
2:3985
2:4059
2:4189
2:4294
2:4342
2:4495
2:456457.6
2:4658
2:476
2:4814
2:4917
2:50100
2:5185
2:5272
2:5393
2:5458
2:55100
2:5632
2:5753
2:5836
2:5976
3:00438.7333333333333
3:0119
3:0232
3:0314
3:0484
3:0526
3:0617
3:0765
3:0820
3:0915
3:1026
3:1152
3:1279
3:1331
3:1497
3:15855.6666666666667
3:1647
3:1787
3:1866
3:1923
3:2088
3:2128
3:2253
3:2387
3:2466
3:2532
3:2671
3:2787
3:2810
3:2982
3:308454.9333333333333
3:3181
3:3254
3:3388
3:3477
3:3598
3:362
3:3715
3:3892
3:3972
3:4016
3:4145
3:424
3:4360
3:4436
3:458463.4666666666667
3:4697
3:4787
3:4829
3:4953
3:5011
3:5184
3:5283
3:5376
3:5464
3:5550
3:5636
3:5783
3:5838
3:5977
4:00364.1333333333333
4:0179
4:0290
4:0391
4:0446
4:0553
4:0626
4:0777
4:0846
4:0962
4:1060
4:1193
4:1278
4:1392
4:1466
4:153537.1333333333333
4:1681
4:1742
4:1850
4:1914
4:2026
4:2172
4:224
4:2315
4:2465
4:2514
4:269
4:2710
4:2838
4:2982
4:301451
4:3148
4:3262
4:3336
4:3489
4:353
4:3653
4:3758
4:3886
4:3971
4:4049
4:4167
4:4220
4:4396
4:4413
4:45047.3333333333333
4:4691
4:4764
4:4828
4:4996
4:5023
4:5137
4:5237
4:5377
4:5415
4:5513
4:5698
4:577
4:5858
4:5966
5:004848.6
5:0122
5:025
5:0376
5:0496
5:055
5:0610
5:073
5:0834
5:0956
5:1082
5:1196
5:1258
5:1380
5:1458
5:154848.1333333333333
5:1630
5:1750
5:1871
5:1912
5:2012
5:2198
5:2224
5:2341
5:2421
5:2566
5:2624
5:2799
5:2873
5:2953
5:30837.3333333333333
5:3167
5:3217
5:330
5:340
5:3537
5:3651
5:3733
5:3828
5:3958
5:403
5:4174
5:4279
5:4390
5:4415
5:455655.7333333333333
5:4682
5:4766
5:4864
5:4969
5:5094
5:5181
5:5223
5:5322
5:5441
5:5516
5:5689
5:5747
5:5874
5:5912
6:007049.2666666666667
6:0172
6:0276
6:0328
6:0462
6:0528
6:0646
6:0762
6:0861
6:0934
6:1052
6:1169
6:1212
6:1337
6:1430
6:157951.8666666666667
6:1635
6:1774
6:1871
6:1912
6:2052
6:2172
6:226
6:2389
6:2416
6:2517
6:2630
6:2764
6:2876
6:2985
6:304742.8666666666667
6:3144
6:3246
6:3346
6:342
6:3583
6:3612
6:3724
6:3847
6:3994
6:4032
6:4170
6:4270
6:4324
6:442
6:457754.2
6:461
6:4727
6:4847
6:4918
6:5075
6:5146
6:5283
6:5358
6:5424
6:5558
6:5681
6:5765
6:5857
6:5996
7:003466.8666666666667
7:0199
7:0279
7:0375
7:0489
7:0592
7:0663
7:0747
7:0849
7:0993
7:1045
7:1140
7:1297
7:1341
7:1460
7:155652.0666666666667
7:1671
7:1792
7:1831
7:1968
7:201
7:213
7:2264
7:2321
7:247
7:2582
7:268
7:2799
7:2896
7:2982
7:309751.4
7:315
7:321
7:3382
7:3467
7:3530
7:3629
7:3789
7:3853
7:3980
7:4014
7:4188
7:4273
7:4336
7:4427
7:455347.4666666666667
7:4647
7:4755
7:484
7:4946
7:5065
7:5147
7:5221
7:5325
7:5451
7:5587
7:5624
7:5746
7:5875
7:5966
8:006341.5333333333333
8:0146
8:0269
8:0358
8:0414
8:0521
8:0683
8:0775
8:0823
8:0912
8:1060
8:1163
8:126
8:139
8:1421
8:155340.6
8:1642
8:1722
8:180
8:1965
8:206
8:2166
8:2216
8:2385
8:248
8:2578
8:2644
8:2786
8:2830
8:298
8:309868.3333333333333
8:3181
8:3293
8:3366
8:3460
8:3527
8:3684
8:3762
8:3881
8:3976
8:4094
8:4119
8:4260
8:4338
8:4486
8:459247.7333333333333
8:4639
8:4718
8:4849
8:4936
8:5057
8:5159
8:5284
8:538
8:5436
8:5514
8:5648
8:5751
8:5867
8:5958
9:007344.7333333333333
9:0190
9:0259
9:032
9:041
9:052
9:0633
9:0751
9:0833
9:0981
9:102
9:1193
9:1279
9:1318
9:1454
9:158748.8666666666667
9:1675
9:1733
9:1819
9:1924
9:2014
9:2145
9:2213
9:2393
9:2454
9:2569
9:2612
9:272
9:2899
9:2994
9:304244.4666666666667
9:3170
9:3283
9:3320
9:3466
9:3510
9:3635
9:3774
9:3818
9:3935
9:407
9:4164
9:4267
9:4355
9:4421
9:454853.4
9:4691
9:4788
9:483
9:4911
9:5045
9:518
9:5220
9:5396
9:5417
9:5576
9:5678
9:5754
9:5899
9:5967
10:001853.5333333333333
10:0152
10:0233
10:0319
10:0465
10:0588
10:0656
10:0799
10:0818
10:0998
10:1050
10:1146
10:1242
10:1353
10:1466
10:156158.5333333333333
10:1684
10:1766
10:1844
10:1943
10:208
10:2126
10:2277
10:2355
10:2485
10:256
10:2691
10:2766
10:2866
10:29100
10:307446.3333333333333
10:3170
10:3210
10:3372
10:3435
10:3519
10:3686
10:3772
10:387
10:3931
10:4095
10:4135
10:4246
10:432
10:4441
10:454546.3333333333333
10:4685
10:473
10:4811
10:4948
10:5090
10:5159
10:5240
10:5326
10:549
10:5594
10:567
10:5770
10:5831
10:5977
11:006747
11:0178
11:0259
11:030
11:0470
11:0577
11:0671
11:0749
11:0851
11:0963
11:1021
11:1121
11:1250
11:1311
11:1417
11:15446.9333333333333
11:1654
11:179
11:1849
11:1930
11:2082
11:2141
11:2222
11:2333
11:2429
11:2578
11:2688
11:2737
11:2884
11:2964
11:302347.4666666666667
11:3150
11:328
11:3350
11:3424
11:3584
11:3653
11:3778
11:3880
11:392
11:4061
11:4189
11:4277
11:4316
11:4417
11:451936.2666666666667
11:4664
11:4785
11:489
11:4930
11:5024
11:515
11:5210
11:5359
11:547
11:5542
11:5621
11:5769
11:5855
11:5945
12:003748.0666666666667
12:0160
12:0285
12:0344
12:0428
12:0589
12:0635
12:0718
12:0848
12:0964
12:103
12:1138
12:1296
12:135
12:1471
12:157146.4
12:1693
12:1737
12:187
12:1938
12:2085
12:2128
12:2286
12:2312
12:2465
12:2538
12:266
12:2766
12:2824
12:2940
12:302642
12:3198
12:3274
12:3313
12:3446
12:3552
12:3639
12:3714
12:3838
12:3925
12:4028
12:4130
12:4244
12:4363
12:4440
12:459641.0666666666667
12:4613
12:4750
12:488
12:4943
12:5027
12:5138
12:5297
12:530
12:5411
12:5584
12:5673
12:5711
12:5820
12:5945
13:003960.1333333333333
13:0194
13:0295
13:0382
13:0439
13:0526
13:0680
13:0770
13:0819
13:0979
13:1074
13:1178
13:1216
13:1320
13:1491
13:155846
13:1667
13:1752
13:1855
13:1947
13:2025
13:218
13:2278
13:2353
13:2455
13:2543
13:269
13:2728
13:2856
13:2956
13:302627.7333333333333
13:315
13:3217
13:332
13:3453
13:359
13:365
13:3763
13:3891
13:3946
13:407
13:4123
13:4225
13:433
13:4441
13:459449.0666666666667
13:4670
13:4749
13:4860
13:4959
13:5051
13:5171
13:5216
13:5337
13:5431
13:5513
13:5664
13:5776
13:5830
13:5915
14:00032.5333333333333
14:016
14:027
14:0313
14:0452
14:0525
14:0653
14:0715
14:0865
14:0970
14:1072
14:1112
14:1223
14:1323
14:1452
14:158750.9333333333333
14:1698
14:1724
14:1860
14:1932
14:2031
14:2110
14:2263
14:2328
14:2420
14:2542
14:2690
14:2743
14:2881
14:2955
14:306053.7333333333333
14:3145
14:3298
14:3396
14:3411
14:3514
14:363
14:3797
14:3863
14:3929
14:4023
14:4196
14:4235
14:4389
14:4447
14:456758.4666666666667
14:4641
14:4766
14:4870
14:4998
14:5047
14:5137
14:5268
14:5361
14:5416
14:5570
14:5619
14:5746
14:58100
14:5971
15:009756.7333333333333
15:0165
15:0299
15:0360
15:0454
15:053
15:0660
15:0779
15:0830
15:0950
15:1037
15:1154
15:1251
15:1363
15:1449
15:152743.0666666666667
15:1610
15:1777
15:1882
15:1915
15:2055
15:2168
15:2274
15:2311
15:240
15:2572
15:2649
15:2762
15:2841
15:293
15:305464.8666666666667
15:3186
15:3295
15:3331
15:3445
15:3571
15:36100
15:3759
15:3843
15:3915
15:4088
15:413
15:4297
15:4388
15:4498
15:457649.7333333333333
15:4617
15:4782
15:4834
15:4964
15:5085
15:5152
15:5229
15:5360
15:5476
15:5516
15:5612
15:5764
15:5852
15:5927
16:008442.8
16:0110
16:0211
16:0313
16:0499
16:0529
16:0664
16:0729
16:0820
16:0964
16:1036
16:1114
16:1238
16:1369
16:1462
16:159652.0666666666667
16:1639
16:1710
16:1880
16:1988
16:2014
16:212
16:224
16:2354
16:2425
16:2578
16:2688
16:2799
16:2889
16:2915
16:307356
16:3168
16:3229
16:3343
16:3426
16:3554
16:3613
16:37100
16:3889
16:3933
16:4048
16:4135
16:4292
16:4356
16:4481
16:453050.1333333333333
16:4699
16:474
16:48100
16:495
16:5010
16:5137
16:5212
16:5392
16:5499
16:5595
16:5669
16:5720
16:5852
16:5928
17:004544.3333333333333
17:0127
17:0220
17:0335
17:0457
17:0588
17:0691
17:077
17:0866
17:0941
17:1020
17:1132
17:1277
17:138
17:1451
17:153853.6
17:1636
17:1739
17:1840
17:1915
17:2091
17:2145
17:2237
17:2399
17:2498
17:2554
17:2664
17:2797
17:2848
17:293
17:305550.6
17:3133
17:3271
17:3340
17:3465
17:3580
17:3646
17:3757
17:3843
17:393
17:4070
17:4130
17:4273
17:4363
17:4430
17:457967.4
17:4667
17:4749
17:4875
17:4998
17:5078
17:5183
17:5283
17:5354
17:5477
17:5546
17:5652
17:5766
17:5864
17:5940
18:009558.8666666666667
18:01100
18:0283
18:0361
18:049
18:0511
18:0635
18:0740
18:0875
18:0980
18:1014
18:1182
18:1237
18:1372
18:1489
18:154845.6666666666667
18:1640
18:1790
18:1827
18:1910
18:2065
18:2152
18:224
18:2329
18:2423
18:2529
18:2690
18:2792
18:281
18:2985
18:306263.2
18:3146
18:3299
18:3350
18:3461
18:3574
18:3690
18:3745
18:3891
18:39100
18:4093
18:4167
18:4219
18:4316
18:4435
18:458658.9333333333333
18:4664
18:4799
18:4826
18:4999
18:5019
18:5131
18:5293
18:5311
18:5474
18:5588
18:5636
18:5756
18:5868
18:5934
19:001869.3333333333333
19:0197
19:0226
19:0384
19:0498
19:0553
19:0679
19:0795
19:0872
19:0992
19:1024
19:1195
19:1286
19:1396
19:1425
19:155058.8
19:1688
19:1795
19:1820
19:1985
19:2041
19:2139
19:2245
19:2367
19:2439
19:2563
19:2698
19:272
19:2861
19:2989
19:309057.8666666666667
19:3174
19:3284
19:3398
19:3483
19:3525
19:3692
19:3772
19:3826
19:3934
19:4048
19:412
19:4270
19:437
19:4463
19:453853.7333333333333
19:4612
19:4744
19:4823
19:490
19:5080
19:5188
19:5288
19:5393
19:5434
19:5569
19:5615
19:5795
19:5885
19:5942
20:003735
20:01100
20:023
20:0317
20:045
20:0544
20:0699
20:0729
20:08100
20:092
20:105
20:1111
20:1225
20:1324
20:1424
20:156340.7333333333333
20:1681
20:1790
20:1844
20:1961
20:2018
20:2137
20:226
20:2385
20:241
20:2553
20:263
20:2754
20:285
20:2910
20:30954.4666666666667
20:3168
20:3289
20:3369
20:3474
20:3550
20:3684
20:3715
20:3858
20:3980
20:4030
20:4169
20:4286
20:4311
20:4425
20:45045.4666666666667
20:4649
20:4729
20:4865
20:4926
20:5062
20:5141
20:5265
20:5327
20:5478
20:5570
20:5617
20:5790
20:585
20:5958
21:002449.4
21:0195
21:0223
21:0316
21:040
21:0525
21:0670
21:0770
21:0885
21:0981
21:1081
21:1190
21:1244
21:139
21:1428
21:156753.1333333333333
21:1689
21:1754
21:1811
21:1917
21:2063
21:2197
21:2288
21:2395
21:2463
21:2565
21:2656
21:2713
21:283
21:2916
21:301455.8
21:3183
21:322
21:3373
21:3481
21:3570
21:365
21:3784
21:3863
21:3988
21:4033
21:4149
21:4290
21:4375
21:4427
21:454353.7333333333333
21:4667
21:4761
21:4817
21:4949
21:5032
21:51100
21:5293
21:5393
21:5453
21:5523
21:5616
21:574
21:5876
21:5979
22:004739.6
22:0146
22:029
22:0392
22:0467
22:052
22:0639
22:0738
22:0852
22:091
22:1015
22:1117
22:1278
22:1314
22:1477
22:157043.8666666666667
22:1658
22:1754
22:1871
22:190
22:2068
22:2110
22:2279
22:2350
22:2457
22:2549
22:260
22:2750
22:285
22:2937
22:305046.8
22:3127
22:3254
22:3339
22:341
22:3588
22:3623
22:3781
22:3870
22:3954
22:4039
22:4152
22:4233
22:432
22:4489
22:45558.9333333333333
22:4678
22:4739
22:4882
22:4979
22:5073
22:5136
22:5275
22:5381
22:5471
22:5540
22:5633
22:5790
22:5838
22:5964
23:001451.2666666666667
23:0127
23:0293
23:0380
23:0412
23:0598
23:069
23:0767
23:0887
23:0910
23:1015
23:1169
23:1260
23:1360
23:1468
23:152159.4666666666667
23:1686
23:1776
23:1821
23:1981
23:2031
23:2171
23:2268
23:2390
23:2463
23:258
23:2685
23:2795
23:2829
23:2967
23:304546.2666666666667
23:3171
23:3273
23:3358
23:3423
23:3516
23:3616
23:3779
23:3884
23:39100
23:404
23:4123
23:4255
23:4325
23:4422
23:45845.4
23:4627
23:4749
23:4822
23:4984
23:5046
23:5124
23:5219
23:5353
23:5432
23:5572
23:5669
23:5796
23:5820
23:5960
Here's the funny part.  The question that was posited essentially asked if the average of the 1 minute data would be more accurate than the average of the 15 minute averages.  Here are the results:

Average of all the 1 minute data points: 49.76319444
Average of all the 15 minute averages: 49.76319444

They're exactly the same!  The reason for this comes from the associative property of addition.  Think about the formula for an average:
x̄ = (a1+a2+a3+...+an)/n

If you had multiple sets (i.e. 15 minute averages):
x̄ = {(a1+a2+a3+...+an)/na + (b1+b2+b3+...+bn)/nb + (c1+c2+c3+...+cn)/nc}/3

Since in this case na=nb=nc, then substitue n and factor out:
x̄ = {(a1+a2+a3+...+an) + (b1+b2+b3+...+bn) + (c1+c2+c3+...+cn)}/3n

Associative property of addition:
x̄ = (a1+a2+a3+...+an+b1+b2+b3+...+bn+c1+c2+c3+...+cn)/3n

Since in this case 3n = n + n + n and na=nb=nc=n, then substitue for n:
x̄ = (a1+a2+a3+...+an+b1+b2+b3+...+bn+c1+c2+c3+...+cn)/(n + n + n)
x̄ = (a1+a2+a3+...+an+b1+b2+b3+...+bn+c1+c2+c3+...+cn)/(na + nb + nc)

Knowing that na + nb + nc is actually the total number of original points gets us back to the original equation for calculating the average of the 1 minute data.  So the average of all the data points is the same as the average of evenly spaced averages of all the data points.  If you're wondering if this works, go ahead and mock it up in Excel.  I did.

Wednesday, January 23, 2013

NetVoyant Duplicates through ODBC

Continuing my effort to document the various ways I've used the ODBC connector for the NetQoS products, here's my next query and controls I've built and that I use in production.  Today's query comes from a need to view duplicate devices and make it easy to eliminate the duplicates.  I had built a fairly extensive method to do this using Perl script and batch files.  It suffered from all the problems that most NPC browser views suffer from.  So, ODBC is a better way to accomplish this and I'm officially retiring that script.  Here's the SelectCommand and OdbcConnection String to put in the configuration.xml:


To create the view, run the following SQL commands against the NPC server:

Wednesday, January 16, 2013

Automating NFA Parser Reports

UPDATE: CA Support has endorsed the NAST tool as the replacement for the NFAParser.  I haven't tested it, but if it's like the other updated tools it will run faster.  The nice thing is that the syntax for running the NAST tool silently is the same as the NFAParser.  So, it doesn't take much to update this tool to use the new tool.

A while back I was tasked with making it possible to view NFA Parser output inside NPC.  It was actually easier than I thought.  I came up with something that isn't as optimal as I would like it (I'll explain why later), but it works for now.

The first thing you have to do is to download the NFA Parser which is part of CA's Support Tools 6 and copy it to each harvester. If you don't want to use all the tools, you can just download the parser and put it on each harvester.  The output of the parser is an HTML file which is ready to be published to a web service so you can link to it from NPC.  The easiest way to do this is to call the parser with a working directory of C:\inetpub\wwwroot on the harvester.  That way the output will be put in that directory, ready to be viewed in a browser.  However, every time you run the parser, the output file's name contains a date/time stamp, so that makes it a little difficult to link to.  The solution is to wrap it all in a batch file that clears the old output, calls the new output, then renames the new output to some static name.  Here's what that batch script would look like:


This could be tweaked a bit to keep the last X files using the following batch script:


This second option moves the existing files up in a queue by renaming them with a higher name, except for the highest one that gets deleted.  So, if I created a scheduled task like this: C:\inetpub\wwwroot\nfa.bat 1 5, I would eventually end up with 5 files, each one representing one of the last 5 runs with nfaout1.htm being the most recent, each spanning 1 minute.  This second method is the option I'm using in production and it seems to work just fine.  In order to easily give access to the files, I create an HTML table with a column for the servers then a column for each of the retained reports.  Then I put in a row for each harvester.  I put that HTML in my custom content directory and load it into a browser view.


Obviously running the report more frequently and with a longer timespan will increase load on the harvester, so don't turn it on to run for 1 minute every minute.

Thursday, January 10, 2013

Giving Existing Users Access to New Data Sources

UPDATE: Turns out I had released a more limited set of commands prevously.  Think of this method as version 2.  It's more complete and replaces the previous method.

There is a limitation in NPC that is a little annoying.  If you have a slew of users created in NPC (either using LDAP integration or just local product authentication) and you add a new data source, only nqadmin and nquser get access to the new data source.  By default, all other users don't get any access to the data source.  This doesn't mean they don't get access to the data, it just means that they can't log into the web GUI for that data source.  The 'proper' action would be to edit every single user and grant them either user, power user, or admin rights to the new data source.  With the advent of SSO and LDAP integration, this just won't work (especially if you have more than a couple dozen users).  And if you've made it a habit to only use the nqadmin account for root level tasks and you are using your own account (setup as an administrator), you would be able to add the data source but not be able to access it until you edit your own user account and give yourself access.  The silly thing is that any new users based on the nqadmin or nquser account would have access to the data source.  The problem is with existing users.

This is a difficult nut to crack; There are a couple features that could be built into NPC that would prevent the data source adder from having to touch every single user:

  1. Give all users no access.  This is what happens now.
  2. Give all users 'user' access to the data source.  This means that you would still have to log edit your own account and grant yourself admin access, not to mention any other accounts that need to be administrators on the new data source.
  3. Give all users except the data source adder 'user' access.  This would allow you immediate admin access, but any other admins would still have to be edited manually.
  4. Give all users the same access to the new data source as they have in NPC.  By this I mean that if a user is an administrator in NPC, they become an administrator for the new data source as well.  If they're a user in NPC, they become a user in NPC.  
  5. Give all cloned users the same access as the account they were cloned from.  So, if a user was cloned from the nquser account (which inherits access to the new data source by default), then that user would also inherit access to the new data source.  
  6. Setup product privilege sets and assign them to users.  I'd create three: all admin, all power user, and all user.  Then I could go to one place to make the change and all the users would be affected.
None of these features are in NPC or is there any indication they will be built into CAPC.  So, in the mean time, here's how you fix it.  The following query will essentially do option #4 above, giving all users the same access to all data sources as they have in NPC.  So, if they're a user in NPC, they'll have user access to all the data sources.  If they're an admin in NPC, they'll have admin access to all the data sources.



There are two ways that this query can be run: 1) scheduled task or 2) manual batch file after adding a data source.  Either way should be sufficient.  Option 2 would be more efficient since this only needs to be done after a new data source is added to NPC.

Monday, January 7, 2013

RA Router List through ODBC

Continuing my effort to document the various ways I've used the ODBC connector for the NetQoS products, here's my next query and controls I've built and that I use in production.  Today's query comes from a need to view the router status for all routers monitored by ReporterAnalyzer (NFA).  The goal is to show a list of the routers along with the address from which RA is receiving Netflow, along with which harvester it's assigned to, how many interfaces have been discovered, how many are enabled, when the router last rebooted, when the last refresh was, and when it was last discovered.  Here's the SelectCommand and OdbcConnection String to put in the configuration.xml:


To create the view, run the following SQL commands against the NPC server:

Thursday, January 3, 2013

iOS App Review: Remote

Remote - AppleApple
Summary - This app gets a ton of usage at our house.  In the last few years, Apple has been improving on their AirPlay feature and Remote reaps the benefits.  This app on my iPhone can connect to any of the iTunes libraries and AppleTVs on my network and control them.  We use this mainly as an additional remote control for our AppleTV.  I can swipe and tap to navigate around the AppleTV UI as well as browse through shared content from my desktop without interrupting the current content on the AppleTV.  When I find a movie, TV show, or music playlist I want to play, the Remote app starts it streaming to the AppleTV.  I can also use this to control music playing on my desktop.  So, if I walk into the other room, I can easily stop the music from playing without going back to my office.  We also use it from time to time to control the iTunes music playing in the nursery (since that PC is a headless PC; e.g. no monitor attached).

Pros - This one is definitely easy to setup.  Just enable the home sharing option by signing in with your Apple ID and you get full control of all the iTunes libraries and devices joined to the home share.  Apple's recent update also added a 'stay-connected' feature that keeps me connected for a few minutes after using the remote.  This means faster resume time if I was just using it a few minutes ago.  The app also supports AirPlay.  I discovered that from the app I can start music playing in my office, then also extend it to the speakers connected to my AppleTV.

Cons - I haven't really found any downsides to the app.  It's well designed and does exactly what I want it to do.


Saturday, December 15, 2012

iOS App Review: Latitude

Google Latitude - Google, Inc.Google Latitude - Google, Inc.
Summary - This handy little app scares people who are paranoid about Google being their big brother.  I look at Google in this way: "If Google wanted any of my information, they'd get it.  So why go to the effort of hiding it?"  Latitude tracks my current GPS position and uploads it regularly to the Google cloud.  Within the app, I have a few defined friends that also use Latitude.  I choose to share my current location with them.  This means I can always check where my wife, my Dad, my brother, and my best friend are.  Hopefully the service won't be turned off without the functionality being moved into Google+.

Pros - Easy to setup, easy to add friends, quick to launch, and I always know if my parents are on their way over for a surprise visit to see the grandkids.  I can also set an option (that's disabled by default) to keep a log of my locations (instead of just my current location).  This could be useful for parents trying to keep an eye on their kids or for catching the crooks that steal your phone.

Cons - Google knows where you've been.  Not many people use it.  It's not yet integrated with Google+ (maybe someday).


Friday, December 14, 2012

iOS App Review: Grabatron

Grabatron - Future Games of LondonGrabatron - Future Games of London

Summary - This game has kept itself on my first page of apps for several months now.  It's a simple game where you fly a UFO by tilting the iPhone.  Tap the screen and a giant claw descends.  The goal is to grab stuff with the claw and destroy it.  Simple gamification techniques make the game easy to put down and resume later while still feeling like I've made progress.  The whole thing has a fun 1950s Aliens Attack! feel to the graphics and theme.

Pros
  • Easy to learn the mechanics of the game
  • In app upgrades can be bought with real money or crystals earned in the game
  • Crystals can also be earned by watching neatly tucked away ads
  • The object of the game is destruction!

Cons
  • Loads slowly on my iPhone4.  Once loaded, performance is fine
  • Music and sound effects were annoying at first.  Easy to disable though

Thursday, December 13, 2012

iOS App Review: Tower Madness

TowerMadness - Limbic SoftwareTowerMadness - Limbic Software

Summary - One of the most fun games I've played.  It's not that much different than other tower defense games, but consistent new maps and tower upgrades keep me coming back and playing the same parts of the game over and over.

Pros
  • New maps released somehow right after I get tired of the existing maps
  • New weapon upgrades released somehow right after I get tired of the existing weapon upgrades
  • Good graphics
  • Easy to learn
  • Endless mode allows for longer play with more money and more aliens to kill
  • Pinch/spread zoom in/out seamlessly integrates with 3D environment
  • 1x/2x/4x play modes so you can play faster

Cons
  • No 'upgrade all the way' or 'upgrade as much as I can afford' option (instead you have to go through each upgrade manually
  • No option in endless mode to send 10/50/100 waves at once (instead you have to tap the single button 10/50/100 times)
  • More maps can be bought as in app purchases - that's how they make money
  • More weapons can be bought as in app purchases
  • 8x play mode would be nice
  • My iPhone 4 slows down when more than 40 waves are present on the playing field and in 4x mode.  Doesn't seem to affect score
  • One tower has an upgrade that turns it into a Tesla Coil.  While it's a great weapon, it doesn't work against airborne enemies.  Since it's all science fiction anyway, I would prefer that this upgrade gave the tower the ability to engage airborne enemies, much like the famed Tesla Death Ray

Wednesday, December 12, 2012

SA Collector Feed List through ODBC

Continuing my effort to document the various ways I've used the ODBC connector for the NetQoS products, I'm going to post a couple of the queries and controls I've built and that I use in production.  Today's query comes from a need to review all the collector feeds for all the collectors on two different master consoles.  Collector feeds are configured for each collection NIC on standard collectors.  I haven't run this query on a MC with a MTP connected, but it should result in the same thing.
The query comes from three different tables and results in a list of feeds and options to edit each collector.  Unfortunately, the functionality to directly modify the feed properties within the GUI isn't present yet, but something like it should be coming soon.  Here's the SelectCommand and OdbcConnection String to put in the configuration.xml:


To create the view, run the following SQL commands against the NPC server:

Tuesday, December 11, 2012

ODBC Connector for NPC

Most of the built in reporting for NPC is great and can be modified by the administrator to get things to look exactly the way they need to be. However, sometimes the built in reports just don't do it. Show my side note.
Specifically, the data that we need to pull is not necessarily available either because the views themselves are limited or because the queries are not the kind of reports that are normally run in NPC or even in the data source. In this case, we have to turn to the ODBC Connector. Not much is known about this, but I was recently introduced to it as a way of bringing external data into NPC. Turns out it's very flexibly and fairly easy to work with.

The ODBC connector allows you to source a table view in NPC with any MySQL query on any server your  connector server has MySQL access to.  So, if you can run the query manually, you can use the query as the source of a view on an NPC page.  Pretty cool huh?  I've built a couple of queries and views into my own NPC.  Now instead of having scheduled tasks that run queries nightly and display that (sometimes stale) output in a browser view, we have dynamic live data in paginated form.  Here's how you do it.

Standard warnings apply: you'll break your stuff, I won't help you fix it, neither will CA support.  Don't do this.  For more details look at the footer of this page.  Make a backup first.

Install the ODBC connector.  Usually this is done on the NPC server, but there's no reason it couldn't be done on one of the data sources or even on a standalone server.  Warning: all NetQoS services on the target server will be stopped as part of the installation, so you'll need to do a reboot at the end of the installation.  Don't worry, you're prompted to do it.

After you get it installed, you'll need to hack NPC a little so you can add it as a data source.  Run the following command on the NPC server.


Now add the ODBC connector as a data source in NPC just like you'd add any other data source.  So far, so good.  Now we need to design our query, build the view that will show the data, and put that view on the page.

I use HeidiSQL because it's easy to look around at things and involves less typing than the command line.  Use whatever you want. Either way, design your query such that you can run it and the output looks the way you would want it to look in NPC.  Don't use spaces in the field names, we will replace the field names later with more readable names.  For example, here's an easy query: select 'Hello World!' as title, 'Nice' as Column2, '1' as Column3;.  This results in one row with three columns.  This query needs to be added to the configuration XML in D:\netqos\portal\integration\ODBC\configuration.xml.  You add it between the <SelectCommands> tags and using a <SelectCommand> tag like this (the tags are probably case sensitive, do it like the ones already there):

Once that's in there, you'll also need to specify a portion of the configuration that will tell the ODBC connector which server to connect to and against which to run the query.  You add it between the <OdbcConnectionStrings> tags with an <OdbcConnectionString> tag liek this:

This should all be self explanatory.  Save the XML configuration and we should be ready to move on to the next step: building the view.

Even though we might be pulling data from the NetVoyant database, we can't use the NetVoyant view wizard to create the views for the ODBC connector.  Luckily, it only takes a few database inserts to create a new view.  Be careful, as removing a view is a bit more complicated than adding a view.  To add a view, simply use the following SQL script.  The comments in the script should be descriptive enough.  Each comment is about the line that follows it.  They key is to make sure the Integration.Parameter.SelectCommandName is the same as the name specified in the ODBC configuration.xml (in this case 'HelloWorld') and that the Integration.Parameter.OdbcConnectionStringName is set to the name specified in the config.xml (in this case 'NetVoyantMC').

INSERT INTO controls
SELECT
-- sets the controlid to the highest unused id below 30000
if(min(id)-1>0,min(id)-1,29999), 
'Hello World', -- name of the view
'Graph',
'ODBC Connector Views', -- category of the view
'/nqWidgets/Integration/wicTable.ascx', 
1, 0x200000, 0, 0, 0, 1, '|nc|g|', '', 'Y'
FROM controls
WHERE datasourcetype=0x200000;

INSERT INTO control_properties
(ControlID, Editable, PropertyName, PropertyValue)
VALUES
-- name of the view
(-1, 'N', 'Title', 'Hello World'), 
-- sql column names separated by semicolon
(-1, 'N', 'DisplayColumns', 'title;column2;column3'), 
-- format of the columns (normally string)
(-1, 'N', 'DisplayFormats', 'string,string,string'), 
-- nice column names
(-1, 'N', 'DisplayNames', 'Message','Column 1','Column 2'),
-- column widths (not sure on units)
(-1, 'N', 'ColumnWidths', ',,'), 
-- alignment of columns
(-1, 'N', 'HorizontalAlignments', 'Left,Center,Right'), 
-- sql column name to sort by
(-1, 'N', 'SortField', 'title'), 
-- desc or asc
(-1, 'N', 'SortDirection', 'Desc'), 
-- name of selectcommand in config.xml (which query to run)
(-1, 'N', 'Integration.Parameter.SelectCommandName', 'HelloWorld'), 
-- don't change this
(-1, 'N', 'Integration.DataType', 'SelectCommand'), 
-- don't change this
(-1, 'N', 'Integration.Parameter.DateTimeFormat', 'yyyy-MM-dd HH:mm'), 
-- max 200
(-1, 'N', 'Integration.Parameter.TopN', '200'), 
-- name of odbcconnectionstring (which server to query)
(-1, 'N', 'Integration.Parameter.OdbcConnectionStringName','NetVoyantMC'); 

UPDATE control_properties 
SET ControlID = (select min(id) from controls where datasourcetype=0x200000)
WHERE ControlID = -1;

You can have selectcommands and odbcconnectionstrings in yours configuration.xml even if they're not used.  

After using the SQL commands above to create the view, simply edit a page and look in the corresponding view category for your new view.  Add it to the page and it should run the query when the page is refreshed, showing updated data.

If you've added the view but need to modify the select query in the config.xml, you'll need to update the corresponding properties to display them.  Also, you can use the 'concat()' and 'convert() using utf8' functions in a query to put advanced html into a particular column (like a link to a certain item's details page). Something like this would give you a row for each collector with links to edit each collector (I'll post the full configuration in my next post):


In the next few posts, I'll post some queries (like the one above) and views that I've built to do some basic reporting in NPC from SuperAgent and NetVoyant.

Monday, December 10, 2012

iOS App Review: Flashlight by Rik

I've been asked before what apps I have installed on my iPhone.  I figured I could detail which ones I use and why through my blog.  This will give me room to put my reasons for/against a certain app.  I'll try to include my overview, pros, and cons.  Here goes nothing...

Flashlight by Rik - Henri Asseily Flashlight by Rik - Henri Asseily
Summary - This turns the iPhone's camera's flash into a flashlight.  Instead of flashing on when taking a picture, this app turns on the flash continuously.
Pros - Tons of options including an option to darken the screen while in use.  When in darkened mode it shows your battery usage so you can keep an eye on things.  It includes standard flashlight functions like auto SOS message through Morse code, manual Morse code, and strobe (more just for fun).  There's also an option to control the intensity, so it can be turned down to make your battery last longer.  It's also free.
Cons - Like any other flashlight app, it will consume battery while it's on.  You can't use other apps and keep the flashlight on.  This is not unique to this flashlight app and has to do more with iOS' so called 'multitasking'.

Monday, December 3, 2012

Automating iTunes

In order to train my kids to go to sleep with ambient noise and without I wanted to setup a way to have music play in their room on some nights and no music playing on other nights.  Given that the holiday season is here, I decided to go ahead and document how I did this.

First of all, I put a small form factor PC in their room on one of the bookshelves behind the books.  I hooked up some cheap speakers to it and installed iTunes.  This was enough to get started.  Since iTunes on that PC was joined to my home share, it was easy to control the music using my iPhone.  There were several problems with this: 1) I had to remember to turn it off or it would be going all night, 2) I had to carve out a section of my iTunes library that would not wake the boys up, and 3) I sometimes had to turn on the music while I was holding a sleeping baby (not easy).  So, I decided to automate things.  A quick Google search led me to Maximize Software's collection of Windows iTunes scripts.  After unpacking the scripts and familiarizing myself with the various options, I started building a batch file that would automate things.

Let's define the objectives:
  1. I want the music to come on and turn off by itself - this should be pretty easy to do using a scheduled task.
  2. I don't want the music to start off at full blast in case we've put the boys down early.    
  3. I want the music to play whenever we put the boys to sleep, which could be as early as 7pm but as late as 9pm.
  4. I want to be able to rotate playlists so it's not the same thing every night.
  5. I want to be able to kick off the music any time.
  6. I want to be able to manually override either the current song or the current volume level.
So, the first thing I did was copy all the music I wanted to play into that computer's iTunes library.  I wanted to be able to use my computer independently of the nursery music, so that meant all the music needed to be local.  The next thing I did was setup a couple of playlists.  The first is called AllMusic and is a smart list with the following criteria: Media Kind = Music & Playlist is not 'Waves' & Playlist is not 'Christmas' & Location = 'on this computer'.  Waves and Christmas are the other two playlists.  Christmas is also a smart play list with the following criteria: Media Kind = Music & Genre = Christmas & Location = 'on this computer'.  Waves is a manual list that contains a single 1 hour 8 minute MP3 of waves crashing on a beach.  The idea behind the playlists is that each playlist gets a night and there would also be one quiet night, setting up a rotation of 4 nights.

The next thing to do was to setup the batch file to play any given playlist, ramp the music up, and ramp the music down.  Here's the batch file:

@echo off
SetVolume.vbs 0
PlayPlaylist.vbs "%1"
for /L %%A IN (0,1,100) DO (
 echo.Increasing volume by 1/sec.
 call:WAITER 1
 SetVolume.vbs +1
)
call:WAITER 7200
for /L %%A IN (100,-1,0) DO (
 echo.Decreasing volume by 1/10 sec.
 call:WAITER 10
 SetVolume.vbs -1
)
Stop.vbs
SetVolume.vbs 100
GOTO:EOF

:WAITER
echo.Waiting for %~1 second(s).
choice /C x /N /T %~1 /D x > NUL
goto:eof

Let me break it down:

@echo off
SetVolume.vbs 0
PlayPlaylist.vbs "%1"
This section starts things off by turning off screen echo, setting the starting volume to 0, then starting to play the playlist provided as the first parameter when calling the batch file.

for /L %%A IN (0,1,100) DO (
 echo.Increasing volume by 1/sec.
 call:WAITER 1
 SetVolume.vbs +1
)
This section ramps up the volume over 100 seconds.  It increases the volume by 1% every 1 second.  This section makes the first use of the WAITER function shown next.  I chose to increment the volume instead of setting the volume to a specific level so that I could manually override the volume.  This means I could use my phone to increase the volume to 100 immediately instead of waiting 100 seconds.  If the script tries to increase the volume to something past 100, the volume just stays at 100.  If this for loop were in its 20th iteration and I had set it to increase to a specific level each time, then if I immediately pushed it up to 100, the next second would push it back to 21.  Not desirable, especially when ramping down the volume.

:WAITER
echo.Waiting for %~1 second(s).
choice /C x /N /T %~1 /D x > NUL
goto:eof
The waiter function simply waits a predetermined number of seconds.  So, if I wanted to wait X seconds, I would just call waiter like this: call:WAITER X.

call:WAITER 7200
This section waits for 7200 seconds which is 2 hours.  This is my 2 hour window; if I start the music at 6:45, it'll still be playing even if we put the boys to bed late.

for /L %%A IN (100,-1,0) DO (
 echo.Decreasing volume by 1/10 sec.
 call:WAITER 10
 SetVolume.vbs -1
)
This section uses the waiter function again to ramp down the volume over 1000 seconds (or 16 minutes and 40 seconds).

Stop.vbs
SetVolume.vbs 100
GOTO:EOF
This section cleans up after everything is over, making the whole thing ready to manually play music during the day if I wanted to.

I put this patch file into the same directory as the scripts and setup 3 scheduled tasks, each starting on a different day and repeating every 4 days:

  1. sleepitunes.bat AllMusic
  2. sleepitunes.bat Christmas
  3. sleepitunes.bat Waves
This has worked pretty well for us.  I've toyed around with doing something like this as an alarm clock, but since the boys were born, I haven't really needed an alarm clock.  However, it wouldn't be very difficult.  The ramp up rate could be changed simply by changing the first call to the waiter function from 'call:WAITER 1' to 'call:WAITER 10'.  

Monday, October 22, 2012

NPC and the footer.text Property


Often when displaying report data, it is handy to have a little explanation about the data being presented.  In the case of NPC, this is accomplished by means of the footer.text property.  As it turns out, this footer.text is HTML based and can use some fairly advanced HTML features.

I say this can be done in NPC, but it can't; at least unless you jailbreak NPC.  At this point, CA has decided that CAPC will replace NPC.  Currently, there's no upgrade path and many of the features that some customers rely upon haven't been rebuilt into CAPC (remember CAPC is a rebuild from the ground up, so just because it was in NPC doesn't mean it will be in CAPC). I've already posted on the community about some of the features that I require before I will upgrade myself or anyone else to CAPC (browser view for example).

However, since NPC now has one foot in the grave (CA is evangelizing IM2.0 which requires CAPC more than Jim Jones' kool-aid), I see no reason why anyone wouldn't want to start experimenting with some of the hidden features in NPC.  So, if you haven't jailbroken NPC yet, you might consider it.  However, if you don't have NV as a data source, don't worry about it.  The NV view wizard is all you really get.  While that opens tons of doors to customization you never thought possible, it doesn't do anything for non-NV customers.  If you're interested, email me.  Once CA puts the last nail in NPC's coffin, I'll publish the steps here.  Until then, I need deniability.

So, on to the topic of this post.  When using the view wizard to create/edit NV views in NV (or NPC if you've jailbroken it) it turns out you can put some fairly complex html in the footer field.  Obviously, you can use {Resolution} and {Samples} in there to pull the current resolution and data point count (whether it's sampled data or not).  However just today I tried and was able to put a fully formed html table in the footer. I then tried to take it a step further and embed a YouTube video.  That worked fine as well.

In case you don't see it, this can be useful when trying to explain to new users what certain views mean.  For example, I could put together a complete page with live data and YouTube videos or text explaining what each one means and how to use it.  For example, I could put some text or an image in the footer that could expand a DIV section containing a YouTube video explaining how to interpret the data.  The nice part about this is that the footer is tied to the view.  Previously, I would put a separate browser view embedding the help information.  This is good for situations where you want to put the data on the left and explanation on the right.  However, putting the explanation in the footer ensures that the explanation stays with the data even through moves and copies.

So in order to put a hidden YouTube video in the footer of a view:

  1. First check to make sure the view supports a footer (most do, this is just a sanity check).
  2. Install HeidiSQL and connect to your NPC server.
  3. Go to the control_properties table and filter it to only show your view.  Get the controlid from the NPC web gui by looking at the status bar when you open the view menu and mouseover the edit option.  Then set a filter for controlid=X, pageid in (0, Y), and propertiesid in (0, Z).
  4. Find the footer.text property.  
  5. Edit the propertyvalue column and insert your html.  
  6. Save the record and you're good to go.
If you change the footer.text where pageid=0, propertiesid=0, and userid=0, you are modifying the default definition of the view and any existing views tied to the default settings and any new views will have this modified setting.
Here's the code you would insert if you wanted to embed my SA video.  You'll need to take out the carriage returns to make it one long line:

Tuesday, October 9, 2012

Windows 8 Highlights

I've been watching (mostly passively) the development and announcements around Windows 8.  Microsoft's new flagship desktop operating system will be unleashed sometime later this month.  I say unleashed, but I really should say released again since there was a developer's preview version of the operating system, a consumer preview version, and a release preview version that were released previously.  In my case, the multiple previews actually cemented a prejudice I have against MS' radical new ideas in their first iteration.  I actually downloaded and installed the developer preview and it told me everything I needed to know about Windows 8: it's the next Windows ME, or Windows Vista and I won't be rushing to it any time soon; Microsoft has tried to do something radically different, but they never get it right on the first try.  It's always the iteration afterward that hits pay-dirt (right after ME was XP and right after Vista was 7).
Either way, Michael Mace put together a great introductory video explaining what changes with this version of the operating system.  Here it is.


Wednesday, October 3, 2012

NQSync

Here's another one of my tools.  I found myself constantly needing to make sure the supportcig.exe is up to date on all my servers.  I also spend a lot of time tweaking my nqbackup.bat script, and every time there's a change, I need to copy it out to all my servers.  I also ended up trying to organize the mess that is the huge quantity of supportcig files distributed across all my servers.  So, of course, I scripted it.



NQSync.bat does several things I'm proud of.  First of all, it finds two unused drive letters on the system on which it's being run, starting with Z.  It does this so that the script can temporarily map network drives out to all the target systems and to the master system.  I should explain: the script can be run from anywhere as long as the credentials used to run the script have admin rights to all the servers.  First it maps a drive to the master server's D: drive.  Then it maps another network drive out to each of the target servers in turn (this is why we need two unused drive letters).  Then, depending on the options will do three actions:

  • Update the supportCIG.exe file on the remote server - the script will copy the supportCIG.exe file from the master's D:\SupportCIG\ directory to the target server(s) D:\SupportCIG\ directory.
    To enable this option, include the switch /u anywhere on the line when calling the script.
  • Gather the supportCIG output files onto the master server - the script will copy any zip files found in D:\SupportCIG\ to the master server into the D:\SupportCIG\[Server]\ directory, where [Server] is the server's name or IP address.
    To enable this option, include the switch /g anywhere on the line when calling the script.
  • Synchronize tools to the remote server - the script will the entire contents of the D:\DBTools3 and D:\SupportTools6 directories out to the remote server in the same location.  This is how I get a copy of my updated nqbackup.bat file out to all the servers.
    To enable this option, include the witch /s anywhere on the line when calling the script.
The script itself will need to be modified to identify the master server.  Just go to line 2 and put the name or IP address of the master server.  Also, you'll need to provide a text file containing the name or IP address of each target server (one per line).  Obviously, it doesn't need to contain the master server's IP address.  Make the path to this text file one of the arguments.  For example:

nqsync.bat /u /g D:\lists\allservers.txt

This would update the CIG and gather all the outputs for all the servers in the text file.  Obviously, if the text file is in the same directory as nqsync.bat, you can exclude the full path and just put the name of the file.

NQSync.bat uses some fun code to find the first and second available drive letters.  I've tested this by using this script.  It identifies which drive letters are in use and which are available.