Tue Jan 16 2018
Copied to clipboard! Copy reply
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
  • 440
  • 441
  • 442
  • 443
  • 444
  • 445
  • 446
  • 447
  • 448
  • 449
  • 450
  • 451
  • 452
  • 453
  • 454
  • 455
  • 456
  • 457
  • 458
  • 459
  • 460
  • 461
  • 462
  • 463
  • 464
  • 465
  • 466
  • 467
  • 468
  • 469
  • 470
  • 471
  • 472
  • 473
  • 474
  • 475
  • 476
  • 477
  • 478
  • 479
  • 480
  • 481
  • 482
  • 483
  • 484
  • 485
  • 486
  • 487
  • 488
  • 489
  • 490
  • 491
  • 492
  • 493
  • 494
  • 495
  • 496
  • 497
  • 498
  • 499
  • 500
  • 501
  • 502
  • 503
  • 504
  • 505
  • 506
  • 507
  • 508
  • 509
  • 510
  • 511
  • 512
  • 513
  • 514
  • 515
  • 516
  • 517
  • 518
  • 519
  • 520
  • 521
  • 522
  • 523
  • 524
  • 525
  • 526
  • 527
  • 528
  • 529
  • 530
  • 531
  • 532
  • 533
  • 534
  • 535
  • 536
  • 537
  • 538
  • 539
  • 540
  • 541
  • 542
  • 543
  • 544
  • 545
  • 546
  • 547
  • 548
  • 549
  • 550
  • 551
  • 552
  • 553
  • 554
  • 555
  • 556
  • 557
  • 558
  • 559
  • 560
  • 561
  • 562
  • 563
  • 564
  • 565
  • 566
  • 567
  • 568
  • 569
  • 570
  • 571
  • 572
  • 573
  • 574
  • 575
  • 576
  • 577
  • 578
  • 579
  • 580
  • 581
  • 582
  • 583
  • 584
  • 585
  • 586
  • 587
  • 588
  • 589
  • 590
  • 591
  • 592
  • 593
  • 594
  • 595
  • 596
  • 597
  • 598
  • 599
  • 600
  • 601
  • 602
  • 603
  • 604
  • 605
  • 606
  • 607
  • 608
  • 609
  • 610
  • 611
  • 612
  • 613
  • 614
  • 615
  • 616
  • 617
  • 618
  • 619
  • 620
  • 621
  • 622
  • 623
  • 624
  • 625
  • 626
  • 627
  • 628
  • 629
  • 630
  • 631
  • 632
  • 633
  • 634
  • 635
  • 636
  • 637
  • 638
  • 639
  • 640
  • 641
  • 642
  • 643
  • 644
  • 645
  • 646
  • 647
  • 648
  • 649
  • 650
  • 651
  • 652
  • 653
  • 654
  • 655
  • 656
  • 657
  • 658
  • 659
  • 660
  • 661
  • 662
  • 663
  • 664
  • 665
  • 666
  • 667
  • 668
  • 669
  • 670
  • 671
  • 672
  • 673
  • 674
  • 675
  • 676
  • 677
  • 678
  • 679
  • 680
  • 681
  • 682
  • 683
  • 684
  • 685
  • 686
  • 687
  • 688
  • 689
  • 690
  • 691
  • 692
  • 693
  • 694
  • 695
  • 696
  • 697
  • 698
  • 699
  • 700
  • 701
  • 702
  • 703
  • 704
  • 705
  • 706
  • 707
  • 708
  • 709
  • 710
  • 711
  • 712
  • 713
  • 714
  • 715
  • 716
  • 717
  • 718
  • 719
  • 720
  • 721
  • 722
  • 723
  • 724
  • 725
  • 726
  • 727
  • 728
  • 729
  • 730
  • 731
  • 732
  • 733
  • 734
  • 735
  • 736
  • 737
  • 738
  • 739
  • 740
  • 741
  • 742
  • 743
  • 744
  • 745
  • 746
  • 747
  • 748
  • 749
  • 750
  • 751
  • 752
  • 753
  • 754
  • 755
  • 756
  • 757
  • 758
  • 759
  • 760
  • 761
  • 762
  • 763
  • 764
  • 765
  • 766
  • 767
  • 768
  • 769
  • 770
  • 771
  • 772
  • 773
  • 774
  • 775
  • 776
  • 777
  • 778
  • 779
  • 780
  • 781
  • 782
  • 783
  • 784
  • 785
  • 786
  • 787
  • 788
  • 789
  • 790
  • 791
  • 792
  • 793
  • 794
  • 795
  • 796
  • 797
  • 798
  • 799
  • 800
  • 801
  • 802
  • 803
  • 804
  • 805
  • 806
  • 807
  • 808
  • 809
  • 810
  • 811
  • 812
  • 813
  • 814
  • 815
  • 816
  • 817
  • 818
  • 819
  • 820
  • 821
  • 822
  • 823
  • 824
  • 825
  • 826
  • 827
  • 828
  • 829
  • 830
  • 831
  • 832
  • 833
  • 834
  • 835
  • 836
  • 837
'use strict';
//INCLUDES:
var gulp = require('gulp');
var fs = require('fs');
var path = require('path');
var lo_ = require('lodash');
var pump = require('pump');
var exec = require('child_process').exec;
var gulpFilter = require('gulp-filter');
const Vinyl = require('Vinyl');
const { Readable } = require('stream');
const { Writable } = require('stream');

//CONFIGS:
//RSIPATH# File path for the RSI File that contains business logic for the pages being compiled

const RSIPATH = path.dirname(__dirname)+"/business-data/models-json/sitewide.json";
var configsrc = 'pageconfigs/us/fra.json';


// OPTIONS:
// --stage
// 	run with --stage to bring {"stage": true} into templates
// --AMP
//  Force styles to run prior to HTML in series (for AMP embedded style requirements)
// --verbose
//  Extra logging for modules
// --size
//  To see input/output sizes for compressions, etc.

//USAGE EXAMPLES:
//gulp
//  compile just the gulpconfig set by the configsrc variable below
//gulp pages --catalogs
//  the directory name must be the first argument
//  *prefer this over gulp full*
//gulp pages --catalogs --loc:es
//  compile all config files in the directory /pageconfigs/catalogs using the 'content-es' branch of the config file
//  *note, this will fail if it does not have content that is required to compile. This is desirable as Gulp cannot magically translate the content for you, so it does the next best thing and warns you loudly that you're missing something*
//gulp pages --contentpages --AMP
//	compile all the AMP pages, (using the --AMP option to force style compilation ahead of html for embedding)




//Full set of configs for full site build
var configs = [
  //For convenience, here is a set of configs that will run with 'gulp full'
  //*Please prefer the more maintainable 'gulp pages' task with gulpconfig files stored properly*
  //This is simply for convenience if you need multiple configs available during development
//   'pageconfigs/us/ara.json',
//   'pageconfigs/us/chi.json',
//   'pageconfigs/us/dar.json',
//   'pageconfigs/us/deu.json',
//   'pageconfigs/us/ebr.json',
//   'pageconfigs/us/eng.json',
//   'pageconfigs/us/esc.json',
  'pageconfigs/us/esp.json',
//   'pageconfigs/us/far.json',
//   'pageconfigs/us/fra.json',
//   'pageconfigs/us/gle.json',
//   'pageconfigs/us/grk.json',
//   'pageconfigs/us/heb.json',
//   'pageconfigs/us/hin.json',
//   'pageconfigs/us/ind.json',
//   'pageconfigs/us/ita.json',
//   'pageconfigs/us/jpn.json',
//   'pageconfigs/us/kis.json',
//   'pageconfigs/us/kor.json',
//   'pageconfigs/us/lat.json',
//   'pageconfigs/us/ned.json',
//   'pageconfigs/us/pas.json',
//   'pageconfigs/us/pol.json',
//   'pageconfigs/us/por.json',
//   'pageconfigs/us/rus.json',
//   'pageconfigs/us/sve.json',
//   'pageconfigs/us/tgl.json',
//   'pageconfigs/us/tur.json',
//   'pageconfigs/us/urd.json',
//   'pageconfigs/us/vie.json',
	// 'pageconfigs/es/ara.json',
	// 'pageconfigs/es/chi.json',
	// 'pageconfigs/es/dar.json',
	// 'pageconfigs/es/deu.json',
	// 'pageconfigs/es/ebr.json',
	// 'pageconfigs/es/eng.json',
	// 'pageconfigs/es/esc.json',
	'pageconfigs/es/esp.json',
	// 'pageconfigs/es/far.json',
	// 'pageconfigs/es/fra.json',
	// 'pageconfigs/es/gle.json',
	// 'pageconfigs/es/grk.json',
	// 'pageconfigs/es/heb.json',
	// 'pageconfigs/es/hin.json',
	// 'pageconfigs/es/ind.json',
	// 'pageconfigs/es/ita.json',
	// 'pageconfigs/es/jpn.json',
	// 'pageconfigs/es/kis.json',
	// 'pageconfigs/es/kor.json',
	//removing latin for now
	//'pageconfigs/es/lat.json',
	// 'pageconfigs/es/ned.json',
	// 'pageconfigs/es/pas.json',
	// 'pageconfigs/es/pol.json',
	// 'pageconfigs/es/por.json',
	// 'pageconfigs/es/rus.json',
	// 'pageconfigs/es/sve.json',
	// 'pageconfigs/es/tgl.json',
	// 'pageconfigs/es/tur.json',
	// 'pageconfigs/es/urd.json',
	// 'pageconfigs/es/vie.json'
]



var args = lo_(process.argv.slice(2))
  .filter(function(v){ return v.match && v.match(/-.+/) })
  .map(function(v){ return v.replace(/^-*/,''); })
  .reduce(function(a,v){ if(v.match(/::/g)){ a[v.split(/::/g)[0]] = v.split(/::/g)[1]; } else {a[v] = true;} return a; }, {});

console.log(JSON.stringify(args));


//for binding business logic into the generator.
//Previously we get RSI.json by running: copy(JSON.stringify(RSI()))
//in Chrome console on http://www.rosettastone.com/lp/sbs/sitewide/
//Now update 'RSI_###.json' to correct pricepoint in the following line.
//each pricepoint rsifile exists in this repo.
//TODO: gulp flag implementation for rsi
var businessdata = JSON.parse( fs.readFileSync(RSIPATH) );

// load plugins
var $ = require('gulp-load-plugins')();


function ObjectsFromReadableStream(src){
	const ret = [];
	//var srcStream = gulp.src('./pageconfigs/us/*.json');
	var srcStream = src;
	
	return new Promise((res,rej)=>{
		let outStream = new Writable({
		  write(chunk, encoding, callback) {
			//console.log('Writable chunk:');
			//console.log(chunk);
			ret.push(chunk);
			callback();
		  },
		  error() {
			rej(ret);  
		  },
		  objectMode: true
		});
		srcStream.on('end', ()=>{ res(ret) });
		srcStream.pipe(outStream);
	});
}

function ReadableFileStream(objs){
	//console.log('getting stream of:');
	//console.log(objs);
	return new Readable({
	  read(size) {
		if(!objs.length){
			return this.push(null);
		}
		var topush = objs.shift();
		//console.log('Pushing to stream:\n');
		//console.log(topush);
		this.push(topush);
	  },
	  objectMode: true
	});
}

const fileCache = {
	cache: new Map(), 
	fetch: function(v){
		let sc = this;
		return (sc.cache.has(v) && sc.cache.get(v)) || (function(){
		    sc.cache.set(v, fs.readFileSync(v));
		    return sc.cache.get(v);
		})();
	}
};

const srcCache = {
    cache: new Map(), 
	fetch: function(v){
		let vk = JSON.stringify(v);
		let sc = this;
		return ( sc.cache.has(vk) && (console.log('Retrieving cache'),true) && Promise.resolve(sc.cache.get(vk)).then((v)=>{ return ReadableFileStream(v.slice()); }) ) || (function(){
			console.log('setting cache for:');
			console.log(v);
		    //sc.cache.set(v, ObjectsFromReadableStream(gulp.src(v)));
			sc.cache.set(vk, ObjectsFromReadableStream(gulp.src(v)) );
			//console.log('cache has:');
			//console.log(sc.cache.has(vk));
			//console.log(sc.cache.get(vk));
		    return Promise.resolve(sc.cache.get(vk)).then((v)=>{ 
				//console.log('getting Stream for:');
				//console.log(v);
				return ReadableFileStream(v.slice()); 
			});
		})();
	}
}


// *********************************************
// STYLES
// *********************************************

gulp.task('styles', function () {
	//var cfgobj = JSON.parse( fs.readFileSync(__dirname + path.sep + configsrc) );
	var cfgobj = JSON.parse( fileCache.fetch(__dirname + path.sep + configsrc) );
	if(cfgobj.styles instanceof Array && cfgobj.styles.length <= 0){
		return;
	}
	var destext = cfgobj.dest;
	var stylessrc = cfgobj.styles || 'build/styles/*.less';

	//Styles are templated with a more limited set of data (from config.json#content)
	console.log(stylessrc);
	
	
	// //using plain gulp.src
	// return gulp.src(stylessrc)
		// .pipe($.template( JSON.parse( fs.readFileSync(__dirname + path.sep + configsrc) ).content || {} ))
		// .pipe($.concat('main.css'))
		// .pipe($.less({
			// strictMath: "on", // to stop less from interfering with calc
			// "options": {
				// "no-ie-compat": true
			// }
		// }))
		// .pipe($.minifyCss())
		// .pipe($.autoprefixer('> 0.02%'))
		// .pipe(gulp.dest('deploy' + (destext ? destext : '') + '/styles'))
	
	
	
	//using srcCache
	return srcCache.fetch(stylessrc)
		.then((gulpsrc)=>{
		//console.log('starting pipeline:');
		gulpsrc
			.pipe($.template( JSON.parse( fs.readFileSync(__dirname + path.sep + configsrc) ).content || {} ))
			.pipe($.concat('main.css'))
			.pipe($.less({
				strictMath: "on", // to stop less from interfering with calc
				"options": {
					"no-ie-compat": true
				}
			}))
			.pipe($.minifyCss())
			.pipe($.autoprefixer('> 0.02%'))
			.pipe(gulp.dest('deploy' + (destext ? destext : '') + '/styles'));
	})
	
		
});

// *********************************************
// SCRIPTS (IN HEAD)
// *********************************************

gulp.task('scripts', function(cb) {
	var cfgobj = JSON.parse( fs.readFileSync(__dirname + path.sep + configsrc) );

	var scriptssrc = cfgobj.scripts || 'build/scripts/*.js';
	var baseopts = scriptssrc ? {base: 'build/scripts/'} : null;
	console.log(scriptssrc);
	var destext = cfgobj.dest;

	
	//plain gulp.src
	// return pump([
		// gulp.src(scriptssrc),
		// $.concat('all.js'),
		// $.uglify(),
		// gulp.dest('deploy' + (destext ? destext : '') + '/scripts')
	// ]);
	
	
	//using srcCache
	return srcCache.fetch(scriptssrc)
		.then((gulpsrc)=>{
			return pump([
				gulpsrc,
				$.concat('all.js'),
				$.uglify(),
				gulp.dest('deploy' + (destext ? destext : '') + '/scripts')
			]);
		})
	
});




// *********************************************
// FOOTER SCRIPTS
// *********************************************

gulp.task('footer_scripts', function(cb) {
	const cfgobj = JSON.parse( fs.readFileSync(__dirname + path.sep + configsrc) );

	const scriptssrc = cfgobj.footer_scripts || 'build/scripts/*.js';
	const baseopts = scriptssrc ? {base: 'build/scripts/'} : null;
	console.log(scriptssrc);
	const destext = cfgobj.dest;

	//with gulp.src
	// return pump([
		// gulp.src(scriptssrc),
		// $.concat('footer_scripts.js'),
		// $.uglify(),
		// gulp.dest('deploy' + (destext ? destext : '') + '/scripts')
	// ]);
	
	//with srcCache
	return srcCache.fetch(scriptssrc)
		.then((gulpsrc)=>{
			return pump([
				gulpsrc,
				$.concat('footer_scripts.js'),
				$.uglify(),
				gulp.dest('deploy' + (destext ? destext : '') + '/scripts')
			]);
		});
	
});








// *********************************************
// ASSETS
// *********************************************

gulp.task('assets', function () {
	return gulp.src('build/assets/**/*')
		.pipe(gulp.dest('deploy/assets'))
});

// moves files from build/assets to deploy/assets
gulp.task('move_assets', function () {
  return gulp.src(['build/assets/*'], { base: 'src' })
    .pipe(gulp.dest('deploy'))
});








function langbranch(_obj, _key) {
    if(!_key || !_obj)
    {
        return {};
    }
    var ret = {};
    var keys = Object.keys(_obj).slice();

    if( ~keys.indexOf(_key) )
    {
        return _obj[_key];
    }
    else
    {
        keys.forEach(function(v){ ret[v] = langbranch(_obj[v], _key); });
    }

    return ret;
}

function RSI(e) {
    function n(e) {
        if (typeof e != "object")
            return [];
        var n = [], r = t.slice(), i = [], s;
        for (var o in e)
            e.hasOwnProperty(o) && i.push([o, e[o]]);
        var u;
        if (!i.length)
            return [];
        while (s = r.pop()) {
            u = !0;
            for (var a = 0, f = i.length; a < f; a++) {
                var l = i[a][0], c = i[a][1];
                if (!s[l] || s[l] !== c)
                    u = !1, a = f
            }
            u && n.push(s)
        }
        return n
    }

	var t = businessdata;

	t = t.concat([
		//placeholder for one-off products: avoid using at all costs. Try to put things in the RSI instead.
	]);
	return e ? n(e) : t
}

function getbusinessdata(rqst) {
	var basereq = !!rqst ? {cat: rqst} : {};
	//console.log('Preparing Business Logic For:');
	//console.log(basereq);
	return function(_index) {
		return RSI(lo_.extend(_index, basereq));
	}
}











// *********************************************
// HTML
// *********************************************

const dom  = require('gulp-dom');
//prefixing styles for AMP process, which needs inlined styles, so 'styles' must be done prior to 'html'
args['AMP'] ? gulp.task('html', ['styles'], gulphtml) : gulp.task('html', gulphtml);

function gulphtml() {
	//Get the "gulpconfig*" file
	var cfgobj = JSON.parse( fs.readFileSync(__dirname + path.sep + configsrc) );
	console.log('processing: ', configsrc);
	var htmlguides = cfgobj.html;
	var contentdata = cfgobj['content' + (args['loc'] ? '-' + args['loc'] : '')];
	var tagsource = {langval: (args['loc'] ? args['loc'] : 'en')};
	var cfgsource = [];
	var indexbasename = "";
	var destext = cfgobj.dest;
	var moduleguides = cfgobj.modules;

	var modules = !moduleguides ? [] : (moduleguides.filter(function(v){
			//filter modules that are not targeted to this market
			return v.match(/::/) ? (v.split('::')[1] === args['loc']) : 1;
		}).map(function(modulename){
			//get modules from names
			console.log('Adding Module: ' + modulename);
			var modret = require(__dirname + path.sep + 'build' + path.sep + 'modules' + path.sep + modulename.split('::')[0] + '.js' );
			modret.gulpname = modulename;
			return modret;
		})
	);

	while (htmlguides.length) {
		(function preparetemplates(_t) {
			tagsource[_t[1]] = fs.readFileSync(__dirname + path.sep + _t[0]);
			cfgsource.push(_t[0]);
			if(_t[1] === "index")
			{
				indexbasename = _t[0].split('/').pop();
			}
		})(htmlguides.pop());
	}

	//apply content variables to tagsource
	!!contentdata && ( tagsource = lo_.defaults(tagsource, contentdata) );

	//apply business logic using the getbusinessdata function (which should use the same source as Landing Pages, to maintain a single point of truth.)
	!!contentdata && ( tagsource = lo_.defaults(tagsource, {"getbusinessdata": getbusinessdata(contentdata && contentdata.content_langcode)}) );
	tagsource = lo_.defaults(tagsource, {"crosssell": getbusinessdata()});
	//Custom to expose to the templater:
	//gettoplvl: can be called in template to query the "top" level product for each type
	tagsource = lo_.defaults(tagsource, {gettoplvl: function(o) {return (getbusinessdata(contentdata && contentdata.content_langcode))(o).sort(function(a,b){return a.lvl === b.lvl ? 0 : a.lvl<b.lvl ? 1 : -1})[0];}});
	//args: give template access to compilation arguments
	tagsource = lo_.defaults(tagsource, args);
	//fs,__dirname,path: template access to file system
	tagsource = lo_.defaults(tagsource, {fs: fs, __dirname: __dirname, path: path});

	//with gulp.src
	//return gulp.src(cfgsource.length ? cfgsource : 'build/*.html')
	return srcCache.fetch(cfgsource.length ? cfgsource : 'build/*.html')
		.then((gulpsrc)=>{
			gulpsrc
			.pipe($.template( tagsource ))
			.pipe($.template( tagsource )) /* 2nd pass to allow for compound templating */
			//.pipe($.htmlhint())
			//.pipe($.htmlhint.reporter())
			.pipe((typeof moduleguides != 'undefined' && moduleguides.length) ? dom(function _chaintransforms(){
				//chain each of the transform functions in module
				modules.reduce(function gettransform(_this, mod, i){
					mod.transforms.reduce(function runtransform(_t, f, j){
						//run the transform and feed it's return value (nominally _this_) back into the
						args['verbose'] && console.log('Applying Module:' + (mod.gulpname + 1) + '::Transform#' + (j + 1));
						return f.call(_t);
					} ,_this);
					return _this;
				}, this);

				return this;
			}) : $.util.noop())
			.pipe(args.size ? $.size() : $.util.noop())
			.pipe($.htmlmin({collapseWhitespace: true, removeComments: true, keepClosingSlash:true, minifyJS: true}))
			.pipe(args.size ? $.size() : $.util.noop())
			.pipe($.rename(function renamehtml(path){
				if ( indexbasename == (path.basename +  path.extname) )
				{
					path.basename = "index";
				}
			}))
			.pipe(gulpFilter(file => /index/.test(file.path) )) // avoid generating unnecessary html files
			.pipe(gulp.dest('deploy' + (destext ? destext : '')))
		});
}

gulp.task('website', ['styles', 'scripts', 'footer_scripts', 'html'], function () {
    console.log('website task finished');

	//commenting this out::
	// return gulp.src('deploy/**/*')
		// .pipe($.size());
});

//for gulp full, we only need to move assets and promos once.
gulp.task('websitefull', ['styles', 'scripts', 'footer_scripts', 'html'], function () {
    return gulp.src('deploy/**/*')
		//.pipe($.size());
});



gulp.task('clean', function () {
    return gulp.src(['deploy/!(assets)'], { read: false }).pipe($.clean());
});

gulp.task('build', ['website'], function(){ return typeof nxt === "function" && nxt(); });

gulp.task('default', ['clean'], function () {
    gulp.start('build');
});


//NEW FULL: only does assets, promos, and pixels once.
gulp.task('full', ['clean'], function () {
	gulp.start('assets');	

	function runconfig(cfg) {
		if (!cfg.length)
		{
			nxt = null;
			return 1;
		}
		console.log('Processing: ' + cfg.slice(-1).pop() + ', #remaining: ' + cfg.length);
		configsrc = cfg.pop();
		var nxt = function(){ return runconfig(cfg); };
		gulp.task(configsrc, ['websitefull'], function(){ return nxt(); });
		gulp.start(configsrc);
	}
	runconfig(configs);
});

gulp.task('stage', ['clean'], function () {
	businessdata = lo_.map(businessdata, function(v){
		v.cart = v.cart ? v.cart.replace(/https/, 'http').replace(/secure/, 'secure.stg') : '';
		return v;
	});

	function runconfig(cfg) {
		if (!cfg.length)
		{
			nxt = null;
			return 1;
		}
		console.log('Processing: ' + cfg.slice(-1).pop() + ', #remaining: ' + cfg.length);
		configsrc = cfg.pop();
		var nxt = function(){ return runconfig(cfg); };
		//define a task, with the name of configsrc, which will:
		  //1. run the website with current cfgsource, which is set above
		  //2. recursively run this function with cfg length reduced by 1
		gulp.task(configsrc, ['website'], function(){ return nxt(); });
		//run the task we just defined.
		gulp.start(configsrc);
	}
	runconfig(configs);
});


gulp.task('connect', function () {
    var connect = require('connect');
    var app = connect()
        .use(require('connect-livereload')({ port: 35729 }))
        .use(connect.static('deploy'))
        .use(connect.directory('deploy'));

    require('http').createServer(app)
        .listen(9000)
        .on('listening', function () {
            console.log('Started connect web server on http://localhost:9000');
        });
});

gulp.task('serve', ['connect'], function () {
    require('opn')('http://localhost:9000');
});

gulp.task('watch', ['connect', 'serve'], function () {
    var server = $.livereload();
    // watch for changes

    gulp.watch([
        'deploy/**/*'
    ]).on('change', function (file) {
        server.changed(file.path);
    });

	gulp.watch('build/**/*.css', ['styles']);
	gulp.watch('build/**/*.less', ['styles']);
	gulp.watch('build/**/*.js', ['scripts']);
	gulp.watch('build/**/*.html', ['html']);
	gulp.watch('build/assets/*.json', ['assets']);

	gulp.watch('../common-modules/**/*.css', ['styles']);
	gulp.watch('../common-modules/**/*.less', ['styles']);
	gulp.watch('../common-modules/**/*.js', ['scripts']);
	gulp.watch('../common-modules/**/*.html', ['html']);
});

gulp.task('filewatch', function () {
	gulp.watch('build/**/*.css', ['styles']);
    gulp.watch('build/**/*.less', ['styles']);
	gulp.watch('build/**/*.js', ['scripts']);
	gulp.watch('build/**/*.html', ['html']);
	gulp.watch('build/assets/*.json', ['assets']);
})

gulp.task('fresh', ['connect'], function () {
    var server = $.livereload();
    // watch for changes

    gulp.watch([
        'deploy/**/*'
    ]).on('change', function (file) {
        server.changed(file.path);
    })
	.on('ready', function(){
		server.changed();
	});

	//setTimeout(function(){ server.listen(9000) }, 2000);
    gulp.watch('build/**/*.css', ['styles']);
    gulp.watch('build/**/*.less', ['styles']);
    //to autoreload for AMP - can remove later
    //gulp.watch('build/**/*.less', ['html']);
	gulp.watch('build/**/*.js', ['scripts']);
	gulp.watch('build/**/*.html', ['html']);
    //gulp.watch('build/assets/**/*.*', ['assets']);
	//gulp.watch('build/assets/*.json', ['assets']);
	//gulp.watch('build/images/*', ['html']);
	
	
});

/* gulp pages
 * performs 'gulp full' on a directory in /pageconfigs
 * e.g. 'gulp pages --catalogs'
*/

gulp.task('pages', function () {
	var args = process.argv.slice(3);
	var dir = args[0];
	if (typeof dir==="undefined") {
		console.log("No directory argument given, using default...");
		gulp.start('full');
		return 1;
	}
	dir = dir.replace(/^--/g,"");
	fs.readdir("pageconfigs/" + dir, function(e,f){
		if (e) {
			console.log("Error: Directory '"+dir+"' not found in pageconfigs");
			console.log("Example input: gulp pages --catalogs");
			return false;
		}
		configs = f.filter(function(i){return i.match(/^gulpconfig.*\.json$/)}).map(function(i){return "pageconfigs/"+dir+"/"+i});

		console.log('Starting full with: \n\t' + configs);
		gulp.start('full');

	});
});

/******************************************************************  
	parsersis:

	This task calls the rsiparser.js program through the 'child_process' module. rsiparser.js is a modified version of the same program that
	was run in the 'rslp' architecture.  It takes the data from the 'data' folder and generates RSI code exposing Rosetta Stone's business
	information to the client-side and deposits them in the /data/models folder.
	
******************************************************************/
gulp.task('parsersis', function(cb) {
  //Create business data models and put them in /data/models/*rsiname*.js for each RSI respectively.
  console.log('\nParsing RSIs...\n');
  var cmd = 'node rsiparser.js';
  if('a' in args || 'all' in args){
	  cmd = 'node rsiparser.js -a';
  }
  else if(Object.getOwnPropertyNames(args).length){
	  cmd = 'node rsiparser.js ' + Object.getOwnPropertyNames(args).shift();
  }
  else {
	  console.warn('Defaulting to sitewide, provide --rsiname or --all to generate campaigns for specific RSIs');
	  cmd = 'node rsiparser.js sitewide';
  }
  console.log('running: ' + cmd);
  
  exec(cmd, function(err, stdout) {
    if (err) return cb(err); // return error
	if(!!stdout){
		console.log(stdout);
	}
    cb(); // finished task
  });

});

/******************************************************************  
	generatelpconfigs:

	This task takes the 'index.json' file in each lp_ pageconfig directory and 'spreads out'
	gulpconfig files that will contain the content & business model info (including sitewide) for each "RSI"-version
	of the landing page build described by the index.json. It also loads the global 'configs' array with a
	reference to each gulpconfig file path so that a 'full' task run after this will compile each config loaded into the array.

	Prior to running, it also calls the 'parsersis' task to generate the rsi model files, although that 
	isn't strictly necessary for this task (it's only set to block on that now because it's difficult to imagine a case
	where you *wouldn't* want the most up-to-date business model available before you compile) and could be separated out in
	the future.	

	It also injects some information to be consumed by the template (rsi_name, mastheadImage name)
******************************************************************/
gulp.task('generatelpconfigs', ['parsersis'], function(cb) {
  console.log('Generating LP Configs from data/models');
  configs = [];
  //get lp_ folders in /pageconfigs
  function getLPConfigFolders(pageconfigpath) {
	var ret = [];
	ret = fs.readdirSync(pageconfigpath).filter(function(v){ return v.match(/^lp_/); }).map(v=> pageconfigpath + path.sep + v);
	return ret;
  }
  function getLPConfigIndex(indexfolderpath) {
	var ret = {};
	var idxpath = indexfolderpath + (indexfolderpath.slice(-1) == path.sep ? '' : path.sep ) + 'index.json';
	if( !!fs.existsSync( idxpath ) ) {
	 var filecontents = fs.readFileSync(idxpath, 'utf-8');
	 return JSON.parse(filecontents);
	}
	else {
	 throw new Error('index.json file does not exist as expected in: ' + indexfolderpath + ' ... try running "rsiparser" first.');
	 return false;
	}
  }
  function getRSIs(rsifolder){
	  var ret = [];
	  ret = fs.readdirSync(rsifolder).filter(function(v){ return v.match(/\.js$/); }).map(v=> [v.replace(/\.js/,''), fs.readFileSync(rsifolder + path.sep + v, 'utf-8')]);

	  return ret;
  }
  let lpfolders = getLPConfigFolders(__dirname + path.sep + 'pageconfigs');
  //lpffolderindexpairs: [bf_catalog...pageconfigs/lp_sbsr/, index.json from that folder]
  let lpfolderindexpairs = lpfolders.map(lppath => [lppath, getLPConfigIndex(lppath)]);
  //console.log(lpfolderindexpairs[0][0]);
  let rsinamejspairs = getRSIs(__dirname + path.sep + 'data' + path.sep + 'models');
  //rsis[0][0] : the rsi name, rsi[0][1] : the rsi compiled .js

  for(let fipair of lpfolderindexpairs){

	  let lppath = fipair[0];
	  let lpname = lppath.split(path.sep).pop().replace('lp_','');
	  lppath += (lppath.slice(-1) == path.sep ? '' : path.sep);
	  let lpindex_obj = fipair[1];

	  console.log('Now generating configs for: ' + lpname + ' @' + lppath);
	  for(let njpair of rsinamejspairs){
		  let rsiname = njpair[0];
		  let rsijs = njpair[1];

		  let index_obj = lo_.clone(lpindex_obj);
		  //append to dest to create proper path:
		  index_obj.dest +=  ( index_obj.dest.slice(-1) == '/' ? '' : '/' ) + rsiname;
		  //append the rsi js to the config file
		  index_obj.content.data_rsi = rsijs;
		  //append the mastheadImage name to template data
		  index_obj.content.data_mastheadImage = (rsijs.match(/mastheadimage:\"([^\"]*)/i) || ['',''])[1];
		  //add rsi name to content:
		  index_obj.content.content_rsiname = rsiname;
		  var write_to = lppath + 'gulpconfig_' + lpname + '_' + rsiname + '.json';
		  //console.log('\t writing: ' + write_to);
		  fs.writeFileSync(write_to, JSON.stringify(index_obj, null, 2));
		  var short_path = write_to.replace(new RegExp('^.*' + path.sep + 'pageconfigs','i'), path.sep + 'pageconfigs');
		  //console.log('writing config: ' + short_path);
		  configs.push(short_path);
	  }
  }
  cb();
});

gulp.task('campaign', ['generatelpconfigs'], function(cb){
	//get all pageconfigs /lp_* directories
		//for each directory:
			//run gulp 'pages' <directory>
	console.log('Starting full with: \n\t' + configs);
	gulp.start('full');
});


gulp.task('move-to-deploy', function () {
	
	gulp.src(['./deploy/**/*','!./deploy/aprende*']) 
	.pipe(gulp.dest('../deploy/catalogs'))
	
	gulp.src(['./deploy/**/*','!./deploy/learn*']) 
	.pipe(gulp.dest('../deploy/espanol'))
	         
});



module.exports = gulp;