<commit_before>/**
 * Created by Skullpluggery on 11/8/2016.
 */

var getUrlParameter = function getUrlParameter(sParam) {
    var sPageURL = decodeURIComponent(window.location.search.substring(1)),
        sURLVariables = sPageURL.split('&'),
        sParameterName,
        i;

    for (i = 0; i < sURLVariables.length; i++) {
        sParameterName = sURLVariables[i].split('=');

        if (sParameterName[0] === sParam) {
            return sParameterName[1] === undefined ? true : sParameterName[1];
        }
    }
};

var area = getUrlParameter('area');

$( document ).ready(function(){

    if(area!=null){
        if(area=="SLEX"){
            GetSLEXStatus();
        }
        else if(area="Bancal"){
            GetBancalStatus();
        }
    }
})

function GetBancalStatus() {

    $("#zoneName").text('Bancal Carmona, Cavite');

}
//
// function GetSLEXStatus() {
//     map.setZoom(16);
//     map.setCenter(slexZoom);
//
//     $("#zoneStatus").show();
//     document.getElementById("aqiText").style.color = slexAirQuality;
//     document.getElementById("AQIStat").style.backgroundColor = slexAirQuality;
//     document.getElementById("zoneName").innerHTML = 'SLEX Carmona Exit, Cavite';
//     document.getElementById("prevalentPollutant").innerHTML = slexprevalentPollutant;
//     document.getElementById("aqiNum").innerHTML = slexAQI;
//     document.getElementById("aqiText").innerHTML = slexAQIStatus;
//     document.getElementById("timeUpdated").innerHTML =  bancal_date_gathered;
//
//     //document.getElementById("e_symbol_1").innerHTML =  "HI";
//     //document.getElementById("concentration_value_1").innerHTML =  "7";
//
//     //alert(bancal_aqi_values[0]);
//
//     for(var i = 0; i < bancal_aqi_values.length; i++)
//     {
//         var elementName = "e_symbol_" + (i+1);
//         var conentrationName = "concentration_value_" + (i+1);
//
//         var elementMin = "aqi_min_" + (i+1);
//         var elementMax = "aqi_max_" + (i+1);
//
//         document.getElementById(elementName).innerHTML =  pollutant_symbols[i];
//         document.getElementById(conentrationName).innerHTML =  bancal_aqi_values[i];
//
//         document.getElementById(elementMin).innerHTML =  parseInt(JSON.stringify(bancal_min_max_values[i][0]).replace(/"/g, ''));
//         document.getElementById(elementMax).innerHTML =  parseInt(JSON.stringify(bancal_min_max_values[i][1]).replace(/"/g, ''));
//     }
//
//     /*
//      for(var i = 0; i < slexValues_array.length; i++)
//      {
//      var elementName = "e_symbol_" + (i+1);
//      var conentrationName = "concentration_value_" + (i+1);
//
//      document.getElementById(elementName).innerHTML =  slexValues_array[i].e_symbol;
//      document.getElementById(conentrationName).innerHTML =  slexValues_array[i].concentration_value;
//      }
//      */
//
//     /*
//      document.getElementById("e_symbol_1").innerHTML =  bancalValues_array[0].e_symbol;
//      document.getElementById("e_symbol_2").innerHTML =  bancalValues_array[1].e_symbol;
//      document.getElementById("e_symbol_3").innerHTML =  bancalValues_array[2].e_symbol;
//      document.getElementById("e_symbol_4").innerHTML =  bancalValues_array[3].e_symbol;
//      document.getElementById("e_symbol_5").innerHTML =  bancalValues_array[4].e_symbol;
//      document.getElementById("e_symbol_6").innerHTML =  bancalValues_array[5].e_symbol;
//      document.getElementById("e_symbol_7").innerHTML =  bancalValues_array[6].e_symbol;
//
//      document.getElementById("concentration_value_1").innerHTML =  bancalValues_array[0].e_symbol;
//      document.getElementById("concentration_value_2").innerHTML =  bancalValues_array[1].e_symbol;
//      document.getElementById("concentration_value_3").innerHTML =  bancalValues_array[2].e_symbol;
//      document.getElementById("concentration_value_4").innerHTML =  bancalValues_array[3].e_symbol;
//      document.getElementById("concentration_value_5").innerHTML =  bancalValues_array[4].e_symbol;
//      document.getElementById("concentration_value_6").innerHTML =  bancalValues_array[5].e_symbol;
//      document.getElementById("concentration_value_7").innerHTML =  bancalValues_array[6].e_symbol;
//      */
// }<commit_msg>img func in daily.php<commit_after>/**
 * Created by Skullpluggery on 11/8/2016.
 */

var getUrlParameter = function getUrlParameter(sParam) {
    var sPageURL = decodeURIComponent(window.location.search.substring(1)),
        sURLVariables = sPageURL.split('&'),
        sParameterName,
        i;

    for (i = 0; i < sURLVariables.length; i++) {
        sParameterName = sURLVariables[i].split('=');

        if (sParameterName[0] === sParam) {
            return sParameterName[1] === undefined ? true : sParameterName[1];
        }
    }
};

var area = getUrlParameter('area');

$( document ).ready(function(){

    if(area!=null){
        if(area=="SLEX"){
            GetSLEXStatus();
        }
        else if(area="Bancal"){
            GetBancalStatus();
        }
    }
})

function GetBancalStatus() {
    $("#zoneName").text('Bancal Carmona, Cavite');
    $("#zoneImg").attr("src","res/images/area/bancal.jpg");
}

function GetSLEXStatus() {
    $("#zoneName").text('SLEX Carmona Exit, Cavite');
    $("#zoneImg").attr("src","res/images/area/slex_carmona-exit.jpg");
}<|endoftext|>


<commit_before>var _ = require('lodash');

// Cleans up an article/chapter object
// remove 'articles' and '_path' attributes
function clean(obj) {
    return obj && _.omit(obj, ['articles', '_path']);
}

// Returns a map of
/*
    {
        "file/path.html": {
            prev: ...,
            next: ...,
        },
        ...
    }
*/
function navigation(summary, files) {
    // Support single files as well as list
    files = _.isArray(files) ? files : (_.isString(files) ? [files] : null);

    // Mapping of prev/next for a give path
    var mapping = {};

    // Special README nav
    var README_NAV = {
        path: 'README.html',
        title: 'Introduction',
    };

    // Walk the chapter/article tree and create navigation entires
    _.each(summary.chapters, function(chapter, idx, chapters) {
        var currentChapter = clean(chapter);
        var prevChapter = (idx-1 < 0) ? README_NAV : chapters[idx-1];
        var nextChapter = (idx+1 >= chapters.length) ? null : chapters[idx+1];

        var prev = (!prevChapter || _.isEmpty(prevChapter.articles)) ?
            prevChapter : _.last(prevChapter.articles);
        var next = (!chapter || _.isEmpty(chapter.articles)) ?
            nextChapter : _.first(chapter.articles);

        // Add chapter mapping
        mapping[chapter.path] = {
            prev: clean(prev),
            next: clean(next),
        };

        // Check a chapter's articles
        _.each(chapter.articles, function(article, _idx, articles) {

            var prev = (_idx-1 < 0) ? currentChapter : clean(articles[_idx-1]);
            var next = (_idx+1 >= articles.length) ? nextChapter : clean(articles[_idx+1]);

            mapping[article.path] = {
                prev: clean(prev),
                next: clean(next),
            };
        });
    });

    // Hack for README.html
    mapping['README.html'] = {
        prev: null,
        next: clean(summary.chapters[0]),
    };

    // Filter for only files we want
    if(files) {
        return _.pick(mapping, files);
    }

    return mapping;
}

// Exports
module.exports = navigation;
<commit_msg>Add level attribute in navigation<commit_after>var _ = require('lodash');

// Cleans up an article/chapter object
// remove 'articles' and '_path' attributes
function clean(obj) {
    return obj && _.omit(obj, ['articles', '_path']);
}

// Returns a map of
/*
    {
        "file/path.html": {
            prev: ...,
            next: ...,
        },
        ...
    }
*/
function navigation(summary, files) {
    // Support single files as well as list
    files = _.isArray(files) ? files : (_.isString(files) ? [files] : null);

    // Mapping of prev/next for a give path
    var mapping = {};

    // Special README nav
    var README_NAV = {
        path: 'README.html',
        title: 'Introduction',
    };

    // Walk the chapter/article tree and create navigation entires
    _.each(summary.chapters, function(chapter, idx, chapters) {
        var currentChapter = clean(chapter);
        var prevChapter = (idx-1 < 0) ? README_NAV : chapters[idx-1];
        var nextChapter = (idx+1 >= chapters.length) ? null : chapters[idx+1];

        var prev = (!prevChapter || _.isEmpty(prevChapter.articles)) ?
            prevChapter : _.last(prevChapter.articles);
        var next = (!chapter || _.isEmpty(chapter.articles)) ?
            nextChapter : _.first(chapter.articles);

        // Add chapter mapping
        mapping[chapter.path] = {
            prev: clean(prev),
            next: clean(next),
            level: (idx+1).toString(),
        };

        // Check a chapter's articles
        _.each(chapter.articles, function(article, _idx, articles) {

            var prev = (_idx-1 < 0) ? currentChapter : clean(articles[_idx-1]);
            var next = (_idx+1 >= articles.length) ? nextChapter : clean(articles[_idx+1]);

            mapping[article.path] = {
                prev: clean(prev),
                next: clean(next),
                level: [idx+1, _idx+1].join('.'),
            };
        });
    });

    // Hack for README.html
    mapping['README.html'] = {
        prev: null,
        next: clean(summary.chapters[0]),
        level: '0',
    };

    // Filter for only files we want
    if(files) {
        return _.pick(mapping, files);
    }

    return mapping;
}

// Exports
module.exports = navigation;
<|endoftext|>


<commit_before>/** Version: 0.7.1 **/
/**
 * Copyright 2008 Toomas Rmer
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
**/
/*
	Representation of the PGN format. Different meta information
	about the actual game(s) plus the moves and result of the game.
*/
function Pgn(pgn) {
	// properties of the game eg players, ELOs etc
	this.props = new Object();
	this.requiredProps = ['Result','Black','White','Date',
								'Round','Site','Event'];
	this.requiredLength = this.requiredProps.length;
	this.moves = new Array();	// the moves, one move contains the black and white move
	this.currentMove = 0;	// the current move in the game
	this.skip = 0;	// which ply? 0=white's, 1=black's

	this.pgnOrig = pgn;
	pgn = this.normalize(pgn);

	this.pgn = pgn;
	this.pgnRaw = this.pgn;
	this.pgnStripped = this.stripComments(this.pgn);

	this.pgn = this.extractTags(this.pgn);

	this.pgn = this.stripComments(this.pgn,true);

	// the moves;
	var themoves = this.pgn.split(" ");
	var ply = new Array();
	ply[1] = null;
	var plyidx = 0;	//make this 1 if FEN and black to move
	if (this.isBlackToMove(this.props['FEN'])) {
		plyidx = 1;
		this.skip = 1;
	}

	var sizeOfTheMoves = this.dropLastMove(themoves) ?
							themoves.length - 1 : themoves.length;

	for (var i=0;i<sizeOfTheMoves;i++) {
		if (themoves[i]) {
			themoves[i] = themoves[i].trim();

			themoves[i] = this.includeOrigination(themoves[i]);
			themoves[i] = this.removeMoveNumber(themoves[i])
			if( themoves[i].length > 0 ) {
				ply[plyidx] = themoves[i];
				if (plyidx == 1) {	//black's move or last move
					var move = new Move(ply[0], ply[1]);
					this.moves[this.moves.length] = move;
					plyidx = 0;
					ply = new Array();
					ply[1] = null;
				}
				else {
					plyidx = 1;
				}
			}
		}
	}

	if (ply[0] || ply[1]) {
		var move = new Move(ply[0], ply[1]);
		this.moves[this.moves.length] = move;
	}
}
/**
 *	Checks FEN to see if it is Black to start
 */
Pgn.prototype.isBlackToMove = function(FEN) {
	return (FEN && / b | B /.test(FEN));
}
/**
 *	Tests to see if last move entry should be dropped. It should be dropped if
 *	it's not a move, but rather a result/partial game indicator.
 */
Pgn.prototype.dropLastMove = function(themoves) {
	return !!themoves[themoves.length-1].match(/1\/2-1\/2|0-1|1-0|\*|\.\.\./);
}
Pgn.prototype.includeOrigination = function(move) {
	if (this.moveHasOrigination(move)) {
		var fromTo = move.split("-");
		var newMove;
		if (fromTo[0].match(/[0-9]*?\.?([A-Z])/) != null) {
			 // we can just replace the - with nothing
			 newMove  = move.replace("-","");
		}
		else {
			var matches = fromTo[0].match(/[0-9]+\./);
			if (matches) {
				newMove = matches[0]+fromTo[1];
			}
			else {
				newMove = fromTo[1];
			}
		}
		return newMove;
	}
	return move;
}
/**
 *	If the move is prefaced by a move number, remove it.
 */
Pgn.prototype.removeMoveNumber = function(move) {
	return move.replace(/^[1-9][0-9]*\.?[ ]*/g,"")
}
/**
 *	will return the pgn string without comments or with comments replaced by dashes.
 */
Pgn.prototype.stripComments = function(pgn, replace) {
	if (this.isBroken(pgn))
		return this.stripItBroken(pgn, replace);
	else
		return this.stripIt(pgn, replace);
}
/**
 *	Does the move have information on its origin as well as its destination
 */
Pgn.prototype.moveHasOrigination = function(move) {
	return move.indexOf("-") != -1
			 && !/[0|o]-[0|o]/i.test(move)
			 && !/[0|o]-[0|o]-[0|o]/i.test(move);
}
/**
 *	This will "normalize" the pgn file by removing line breaks, collapsing strings of
 *	spaces, and replacing the symbols for moves with the characters (!, ?, etc.)
 */
Pgn.prototype.normalize = function(pgn) {
	pgn = pgn.replace(/\n/g," ");

	// replace dollar signs
	//"!", "?", "!!", "!?", "?!", and "??"
	pgn = pgn.replace(/\ \$1[0-9]*/g, "!");
	pgn = pgn.replace(/\ \$2[0-9]*/g, "?");
	pgn = pgn.replace(/\ \$3[0-9]*/g, "!!");
	pgn = pgn.replace(/\ \$4[0-9]*/g, "??");
	pgn = pgn.replace(/\ \$5[0-9]*/g, "!?");
	pgn = pgn.replace(/\ \$6[0-9]*/g, "?!");
	pgn = pgn.replace(/\ \$[0-9]+/g, "");

	// make double spaces to single spaces
	return pgn.replace(/\s+/g,' ');
}
/**
 *	This function takes a pgn game string and extracts all the tags into the class
 *	variable props as key/value pairs. it returns the pgn string, minus the tags.
 */
Pgn.prototype.extractTags = function (pgn) {
	var matches;
	var reprop = /\[([^\]]*)\]/gi;
	if (matches = pgn.match(reprop)) {
		// extract information from each matched property
		for(var i = 0;i < matches.length; i++) {
			// lose the brackets
			tmpMatches = matches[i].substring(1, matches[i].length-1);
			// split by the first space
			var key = tmpMatches.substring(0, tmpMatches.indexOf(" "));
			var value = tmpMatches.substring(tmpMatches.indexOf(" ")+1);
			if (value.charAt(0) == '"')
				value = value.substr(1);
			if (value.charAt(value.length-1) == '"')
				value = value.substr(0, value.length-1);

			this.props[key] = value;
			pgn = pgn.replace(matches[i], "");
		}
	}
	length = this.requiredLength;
	while(length--) {
		if(!this.props[this.requiredProps[length]])
			this.props[this.requiredProps[length]] = "?";
	}

	return pgn.replace(/\[[^\]]*\]/g,'').trim();
}

Pgn.prototype.nextMove = function() {
		var rtrn = null;
		try{
			if (this.skip) {
				this.skip = 0;
				rtrn = new Array(this.moves[this.currentMove].black,
													'black');
				this.currentMove++;
			}
			else {
				this.skip = 1;
				rtrn = new Array(this.moves[this.currentMove].white,
											'white');
			}

			if (rtrn[0] == null || rtrn[0].length == 0)
				rtrn = null;
			return rtrn;
		}
		catch (e) {
			return null;
		}
	};

Pgn.prototype.getComment = function(move, idx) {
		var i = this.pgnStripped.indexOf(move,idx);
		if (i == -1) {
			//throw("getComment error, could not find move '"
			//				+move+"'"+", with index '"+idx+"'");
			return [null,idx];
		}

		for (var j=i+move.length;j<this.pgnStripped.length;j++) {
			var c = this.pgnStripped.charAt(j);
			switch (c) {
				case ' ':
					break;
				case '_':	//found comment
					for (var k=j;k<this.pgnStripped.length;k++) {
						var c2 = this.pgnStripped.charAt(k);
						switch (c2) {
							case '_':	//found comment
								break;
							default:	//no comment
								// we might have many comments separated with spaces
								// as we strip all double spaces to single ones we
								// can just check for the next char being '_'
								if (this.pgnStripped.length>k+1
									 	&& this.pgnStripped.charAt(k+1) == '_') {
									continue;
								}
								return [this.pgnRaw.substring(j,k),k];
						}
					}
					break;
				default:	//no comment
					return [null,idx];
			}
		}
		return [null,idx];
	};

Pgn.prototype.isBroken = function (val) {
		var pCount = 0;
		var cCount = 0;
		var lastOne = "";
		var inComment = false;
		for (var i=0;i<val.length;i++) {
			var c = val.charAt(i);
			if(inComment) {
				switch (c) {
					case '}':
						inComment = false;
						// closing a non-existent curly brace
						if (cCount == 0)
							return true;
						// if we're closing a parenthesis instead of a curly
						if (lastOne == "p")
							return true;
						lastOne = "";
						cCount--;
						break;
					case '{':
						// Cannot nest comments
						return true;
				}
			} else {
				switch (c) {
					case '(':
						pCount++;
						lastOne = "p";
						break;
					case ')':
						// closing a non-existent curly brace
						if (pCount == 0)
							return true;
						// closing a curly instead of a parenthesis
						if (lastOne == "c")
							return true;
						lastOne = "";
						pCount--;
						break;
					case '{':
						inComment = true;
						cCount++;
						lastOne = "c";
						break;
				}
			}
		}
		return false;
	};

Pgn.prototype.stripItBroken = function (val, strip) {
	var count = 0;
	var out = new Array();
	/*
		At one point chesspastebin.com started getting cames
		with invalid PGNs, mostly in the form
		{ comment comment ( something between starting brackets}.
		As you can see, the ( is not closed.
		isOpen and isCurlyO are just for that to take normal
		guesses in that kind of situations.
	*/
	var isOpen = false;
	var isCurlyO = false;
	var curlyOpenedFst = false;
	for (var i=0;i<val.length;i++) {
		var c = val.charAt(i);
		switch (c) {
			case '(':
				if (!strip) {
					out[out.length] = '_';
				}
				count++;
				if (isOpen) {
					 	count--;
				}
				isOpen = true;
				break;
			case '{':
				isCurlyO = true;
				if (!strip) {
					out[out.length] = '_';
				}
				count++;
				if (!isOpen)
					 curlyOpenedFst=true;
				break;
			case '}':
				if (isOpen && isCurlyO && curlyOpenedFst) {
					// lets close the open (
					count--;
					isOpen = false;
				}
				isCurlyO = false;
				curlyOpenedFst = false;
				count--;
				if (!strip) {
					out[out.length] = '_';
				}
				break;
			case ')':
				if (isOpen) {
					 count--;
					 if (!strip) {
						 out[out.length] = '_';
					 }
					 isOpen = false;
				}
				break;
			case '\t':
				out[out.length] = ' ';
				break;
			default:
				if (count > 0) {
					if (!strip) {
						out[out.length] = '_';
					}
				}
				else {
					out[out.length] = c;
				}
		}
	}
	return out.join("");
};

/*
	Strip game comments from a PGN string. If second
	parameter set false true then comments will be replaced
	by an underscore.
*/
Pgn.prototype.stripIt = function (val, strip) {
	var count = 0;
	var out = new Array();
	var inComment = false;
	for (var i=0;i<val.length;i++) {
		var c = val.charAt(i);
		switch (c) {
			case '(':
				if (!strip) {
					out[out.length] = '_';
				}
				if(!inComment) {
					count++;
				}
				break;
			case '{':
				inComment = true;
				if (!strip) {
					out[out.length] = '_';
				}
				count++;
				break;
			case '}':
				count--;
				if (!strip) {
					out[out.length] = '_';
				}
				inComment = false;
				break;
			case ')':
				if(!inComment) {
					count--;
				}
				if (!strip) {
					out[out.length] = '_';
				}
				break;
			case '\t':
				out[out.length] = ' ';
				break;
			default:
				if (count > 0) {
					if (!strip) {
						out[out.length] = '_';
					}
				}
				else {
					out[out.length] = c;
				}
		}
	}
	return out.join("");
};
<commit_msg>Code cleanup<commit_after>/** Version: 0.7.1 **/
/**
 * Copyright 2008 Toomas Rmer
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
**/
/*
	Representation of the PGN format. Different meta information
	about the actual game(s) plus the moves and result of the game.
*/
function Pgn(pgn) {
	// properties of the game eg players, ELOs etc
	this.props = new Object();
	this.requiredProps = ['Result','Black','White','Date',
								'Round','Site','Event'];
	this.requiredLength = this.requiredProps.length;
	this.moves = new Array();	// the moves, one move contains the black and white move
	this.currentMove = 0;	// the current move in the game
	this.skip = 0;	// which ply? 0=white's, 1=black's

	this.pgnOrig = pgn;
	pgn = this.normalize(pgn);

	this.pgn = pgn;
	this.pgnRaw = this.pgn;
	this.pgnStripped = this.stripComments(this.pgn);

	this.pgn = this.extractTags(this.pgn);
	this.pgn = this.stripComments(this.pgn,true);

	var themoves = this.pgn.split(" ");
	var ply = new Array();
	ply[1] = null;
	var plyidx = 0;	//make this 1 if FEN and black to move
	if (this.isBlackToMove(this.props['FEN'])) {
		plyidx = 1;
		this.skip = 1;
	}

	var sizeOfTheMoves = this.dropLastMove(themoves) ?
							themoves.length - 1 : themoves.length;

	for (var i=0;i<sizeOfTheMoves;i++) {
		if (themoves[i]) {
			themoves[i] = themoves[i].trim();

			themoves[i] = this.includeOrigination(themoves[i]);
			themoves[i] = this.removeMoveNumber(themoves[i])
			if( themoves[i].length > 0 ) {
				ply[plyidx] = themoves[i];
				if (plyidx == 1) {	//black's move or last move
					var move = new Move(ply[0], ply[1]);
					this.moves[this.moves.length] = move;
					plyidx = 0;
					ply = new Array();
					ply[1] = null;
				}
				else {
					plyidx = 1;
				}
			}
		}
	}

	if (ply[0] || ply[1]) {
		var move = new Move(ply[0], ply[1]);
		this.moves[this.moves.length] = move;
	}
}
/**
 *	Checks FEN to see if it is Black to start
 */
Pgn.prototype.isBlackToMove = function(FEN) {
	return (FEN && / b | B /.test(FEN));
}
/**
 *	Tests to see if last move entry should be dropped. It should be dropped if
 *	it's not a move, but rather a result/partial game indicator.
 */
Pgn.prototype.dropLastMove = function(themoves) {
	return !!themoves[themoves.length-1].match(/1\/2-1\/2|0-1|1-0|\*|\.\.\./);
}
Pgn.prototype.includeOrigination = function(move) {
	if (this.moveHasOrigination(move)) {
		var fromTo = move.split("-");
		var newMove;
		if (fromTo[0].match(/[0-9]*?\.?([A-Z])/) != null) {
			 // we can just replace the - with nothing
			 newMove  = move.replace("-","");
		}
		else {
			var matches = fromTo[0].match(/[0-9]+\./);
			if (matches) {
				newMove = matches[0]+fromTo[1];
			}
			else {
				newMove = fromTo[1];
			}
		}
		return newMove;
	}
	return move;
}
/**
 *	If the move is prefaced by a move number, remove it.
 */
Pgn.prototype.removeMoveNumber = function(move) {
	return move.replace(/^[1-9][0-9]*\.?[ ]*/g,"")
}
/**
 *	will return the pgn string without comments or with comments replaced by dashes.
 */
Pgn.prototype.stripComments = function(pgn, replace) {
	if (this.isBroken(pgn))
		return this.stripItBroken(pgn, replace);
	else
		return this.stripIt(pgn, replace);
}
/**
 *	Does the move have information on its origin as well as its destination
 */
Pgn.prototype.moveHasOrigination = function(move) {
	return move.indexOf("-") != -1
			 && !/[0|o]-[0|o]/i.test(move)
			 && !/[0|o]-[0|o]-[0|o]/i.test(move);
}
/**
 *	This will "normalize" the pgn file by removing line breaks, collapsing strings of
 *	spaces, and replacing the symbols for moves with the characters (!, ?, etc.)
 */
Pgn.prototype.normalize = function(pgn) {
	pgn = pgn.replace(/\n/g," ");

	// replace dollar signs
	//"!", "?", "!!", "!?", "?!", and "??"
	pgn = pgn.replace(/\ \$1[0-9]*/g, "!");
	pgn = pgn.replace(/\ \$2[0-9]*/g, "?");
	pgn = pgn.replace(/\ \$3[0-9]*/g, "!!");
	pgn = pgn.replace(/\ \$4[0-9]*/g, "??");
	pgn = pgn.replace(/\ \$5[0-9]*/g, "!?");
	pgn = pgn.replace(/\ \$6[0-9]*/g, "?!");
	pgn = pgn.replace(/\ \$[0-9]+/g, "");

	// make double spaces to single spaces
	return pgn.replace(/\s+/g,' ');
}
/**
 *	This function takes a pgn game string and extracts all the tags into the class
 *	variable props as key/value pairs. it returns the pgn string, minus the tags.
 */
Pgn.prototype.extractTags = function (pgn) {
	var matches;
	var reprop = /\[([^\]]*)\]/gi;
	if (matches = pgn.match(reprop)) {
		// extract information from each matched property
		for(var i = 0;i < matches.length; i++) {
			// lose the brackets
			tmpMatches = matches[i].substring(1, matches[i].length-1);
			// split by the first space
			var key = tmpMatches.substring(0, tmpMatches.indexOf(" "));
			var value = tmpMatches.substring(tmpMatches.indexOf(" ")+1);
			if (value.charAt(0) == '"')
				value = value.substr(1);
			if (value.charAt(value.length-1) == '"')
				value = value.substr(0, value.length-1);

			this.props[key] = value;
			pgn = pgn.replace(matches[i], "");
		}
	}
	length = this.requiredLength;
	while(length--) {
		if(!this.props[this.requiredProps[length]])
			this.props[this.requiredProps[length]] = "?";
	}

	return pgn.replace(/\[[^\]]*\]/g,'').trim();
}

Pgn.prototype.nextMove = function() {
		var rtrn = null;
		try{
			if (this.skip) {
				this.skip = 0;
				rtrn = new Array(this.moves[this.currentMove].black,
													'black');
				this.currentMove++;
			}
			else {
				this.skip = 1;
				rtrn = new Array(this.moves[this.currentMove].white,
											'white');
			}

			if (rtrn[0] == null || rtrn[0].length == 0)
				rtrn = null;
			return rtrn;
		}
		catch (e) {
			return null;
		}
	};

Pgn.prototype.getComment = function(move, idx) {
		var i = this.pgnStripped.indexOf(move,idx);
		if (i == -1) {
			//throw("getComment error, could not find move '"
			//				+move+"'"+", with index '"+idx+"'");
			return [null,idx];
		}

		for (var j=i+move.length;j<this.pgnStripped.length;j++) {
			var c = this.pgnStripped.charAt(j);
			switch (c) {
				case ' ':
					break;
				case '_':	//found comment
					for (var k=j;k<this.pgnStripped.length;k++) {
						var c2 = this.pgnStripped.charAt(k);
						switch (c2) {
							case '_':	//found comment
								break;
							default:	//no comment
								// we might have many comments separated with spaces
								// as we strip all double spaces to single ones we
								// can just check for the next char being '_'
								if (this.pgnStripped.length>k+1
									 	&& this.pgnStripped.charAt(k+1) == '_') {
									continue;
								}
								return [this.pgnRaw.substring(j,k),k];
						}
					}
					break;
				default:	//no comment
					return [null,idx];
			}
		}
		return [null,idx];
	};

Pgn.prototype.isBroken = function (val) {
		var pCount = 0;
		var cCount = 0;
		var lastOne = "";
		var inComment = false;
		for (var i=0;i<val.length;i++) {
			var c = val.charAt(i);
			if(inComment) {
				switch (c) {
					case '}':
						inComment = false;
						// closing a non-existent curly brace
						if (cCount == 0)
							return true;
						// if we're closing a parenthesis instead of a curly
						if (lastOne == "p")
							return true;
						lastOne = "";
						cCount--;
						break;
					case '{':
						// Cannot nest comments
						return true;
				}
			} else {
				switch (c) {
					case '(':
						pCount++;
						lastOne = "p";
						break;
					case ')':
						// closing a non-existent curly brace
						if (pCount == 0)
							return true;
						// closing a curly instead of a parenthesis
						if (lastOne == "c")
							return true;
						lastOne = "";
						pCount--;
						break;
					case '{':
						inComment = true;
						cCount++;
						lastOne = "c";
						break;
				}
			}
		}
		return false;
	};

Pgn.prototype.stripItBroken = function (val, strip) {
	var count = 0;
	var out = new Array();
	/*
		At one point chesspastebin.com started getting cames
		with invalid PGNs, mostly in the form
		{ comment comment ( something between starting brackets}.
		As you can see, the ( is not closed.
		isOpen and isCurlyO are just for that to take normal
		guesses in that kind of situations.
	*/
	var isOpen = false;
	var isCurlyO = false;
	var curlyOpenedFst = false;
	for (var i=0;i<val.length;i++) {
		var c = val.charAt(i);
		switch (c) {
			case '(':
				if (!strip) {
					out[out.length] = '_';
				}
				count++;
				if (isOpen) {
					 	count--;
				}
				isOpen = true;
				break;
			case '{':
				isCurlyO = true;
				if (!strip) {
					out[out.length] = '_';
				}
				count++;
				if (!isOpen)
					 curlyOpenedFst=true;
				break;
			case '}':
				if (isOpen && isCurlyO && curlyOpenedFst) {
					// lets close the open (
					count--;
					isOpen = false;
				}
				isCurlyO = false;
				curlyOpenedFst = false;
				count--;
				if (!strip) {
					out[out.length] = '_';
				}
				break;
			case ')':
				if (isOpen) {
					 count--;
					 if (!strip) {
						 out[out.length] = '_';
					 }
					 isOpen = false;
				}
				break;
			case '\t':
				out[out.length] = ' ';
				break;
			default:
				if (count > 0) {
					if (!strip) {
						out[out.length] = '_';
					}
				}
				else {
					out[out.length] = c;
				}
		}
	}
	return out.join("");
};

/*
	Strip game comments from a PGN string. If second
	parameter set false true then comments will be replaced
	by an underscore.
*/
Pgn.prototype.stripIt = function (val, strip) {
	var count = 0;
	var out = new Array();
	var inComment = false;
	for (var i=0;i<val.length;i++) {
		var c = val.charAt(i);
		switch (c) {
			case '(':
				if (!strip) {
					out[out.length] = '_';
				}
				if(!inComment) {
					count++;
				}
				break;
			case '{':
				inComment = true;
				if (!strip) {
					out[out.length] = '_';
				}
				count++;
				break;
			case '}':
				count--;
				if (!strip) {
					out[out.length] = '_';
				}
				inComment = false;
				break;
			case ')':
				if(!inComment) {
					count--;
				}
				if (!strip) {
					out[out.length] = '_';
				}
				break;
			case '\t':
				out[out.length] = ' ';
				break;
			default:
				if (count > 0) {
					if (!strip) {
						out[out.length] = '_';
					}
				}
				else {
					out[out.length] = c;
				}
		}
	}
	return out.join("");
};
<|endoftext|>


<commit_before>const Clutter    = imports.gi.Clutter;
const Gio        = imports.gi.Gio;
const Lang       = imports.lang;
const Mainloop   = imports.mainloop;
const Meta       = imports.gi.Meta;
const Shell      = imports.gi.Shell;
const St         = imports.gi.St;
const PolicyType = imports.gi.Gtk.PolicyType;
const Util       = imports.misc.util;

const Main      = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const CheckBox  = imports.ui.checkBox.CheckBox;

const Gettext = imports.gettext;
const _ = Gettext.domain('clipboard-indicator').gettext;

const Clipboard = St.Clipboard.get_default();
const CLIPBOARD_TYPE = St.ClipboardType.CLIPBOARD;

const SETTING_KEY_CLEAR_HISTORY = "clear-history";
const SETTING_KEY_PREV_ENTRY = "prev-entry";
const SETTING_KEY_NEXT_ENTRY = "next-entry";
const SETTING_KEY_TOGGLE_MENU = "toggle-menu";

const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Utils = Me.imports.utils;
const Prefs = Me.imports.prefs;
const prettyPrint = Utils.prettyPrint;
const writeRegistry = Utils.writeRegistry;
const readRegistry = Utils.readRegistry;

let TIMEOUT_MS           = 1000;
let MAX_REGISTRY_LENGTH  = 15;
let MAX_ENTRY_LENGTH     = 50;
let DELETE_ENABLED       = true;
let ENABLE_KEYBINDING    = true;
let PRIVATEMODE          = false;

const ClipboardIndicator = Lang.Class({
    Name: 'ClipboardIndicator',
    Extends: PanelMenu.Button,

    _settingsChangedId: null,
    _clipboardTimeoutId: null,
    _historyLabelTimeoutId: null,
    _historyLabel: null,
    _shortcutsBindingIds: [],
    clipItemsRadioGroup: [],

    destroy: function () {
        this._disconnectSettings();
        this._unbindShortcuts();
        this._clearClipboardTimeout();
        this._clearLabelTimeout();

        // Call parent
        this.parent();
    },

    _init: function() {
        this.parent(0.0, "ClipboardIndicator");
        let hbox = new St.BoxLayout({ style_class: 'panel-status-menu-box clipboard-indicator-hbox' });
        this.icon = new St.Icon({ icon_name: 'edit-paste-symbolic',
            style_class: 'system-status-icon clipboard-indicator-icon' });

        hbox.add_child(this.icon);
        this.actor.add_child(hbox);

        this._createHistoryLabel();
        this._loadSettings();
        this._buildMenu();
        this._setupTimeout();
    },

    _buildMenu: function () {
        let that = this;
        this._getCache(function (clipHistory) {
            let lastIdx = clipHistory.length - 1;
            let clipItemsArr = that.clipItemsRadioGroup;

            // Create menu section for items
            that.historySection = new PopupMenu.PopupMenuSection();

            that.scrollViewMenuSection = new PopupMenu.PopupMenuSection();
            let historyScrollView = new St.ScrollView({
                style_class: 'ci-history-menu-section',
                overlay_scrollbars: true
            });
            historyScrollView.add_actor(that.historySection.actor);

            that.scrollViewMenuSection.actor.add_actor(historyScrollView);

            that.menu.addMenuItem(that.scrollViewMenuSection);

            // Add cached items
            clipHistory.forEach(function (buffer) {
                that._addEntry(buffer);
            });

            // Add separator
            that.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());

            // Private mode switch
            that.privateModeMenuItem = new PopupMenu.PopupSwitchMenuItem(_("Private mode"), PRIVATEMODE, { reactive: true });
            that.privateModeMenuItem.connect('toggled', Lang.bind(that, that._onPrivateModeSwitch));
            that.menu.addMenuItem(that.privateModeMenuItem);

            // Add 'Clear' button which removes all items from cache
            let clearMenuItem = new PopupMenu.PopupMenuItem(_('Clear history'));
            that.menu.addMenuItem(clearMenuItem);
            clearMenuItem.connect('activate', Lang.bind(that, that._removeAll));

            // Add 'Settings' menu item to open settings
            let settingsMenuItem = new PopupMenu.PopupMenuItem(_('Settings'));
            that.menu.addMenuItem(settingsMenuItem);
            settingsMenuItem.connect('activate', Lang.bind(that, that._openSettings));

            if (lastIdx >= 0) {
                that._selectMenuItem(clipItemsArr[lastIdx]);
            }
        });
    },

    _setEntryLabel: function (menuItem) {
        let buffer = menuItem.clipContents,
        shortened = buffer.substr(0,MAX_ENTRY_LENGTH).replace(/\s+/g, ' ');

        if (buffer.length > MAX_ENTRY_LENGTH)
            shortened += '...';

        menuItem.label.set_text(shortened);
    },

    _addEntry: function (buffer, autoSelect, autoSetClip) {
        let menuItem = new PopupMenu.PopupMenuItem('');

        menuItem.menu = this.menu;
        menuItem.clipContents = buffer;
        menuItem.radioGroup = this.clipItemsRadioGroup;
        menuItem.buttonPressId = menuItem.connect('activate',
            Lang.bind(menuItem, this._onMenuItemSelected));

        this._setEntryLabel(menuItem);
        this.clipItemsRadioGroup.push(menuItem);

        let icon = new St.Icon({
            icon_name: 'edit-delete-symbolic', //'mail-attachment-symbolic',
            style_class: 'system-status-icon'
        });

        let icoBtn = new St.Button({
            style_class: 'ci-action-btn',
            x_fill: true,
            can_focus: true,
            child: icon
        });

        icoBtn.set_x_align(Clutter.ActorAlign.END);
        icoBtn.set_x_expand(true);
        icoBtn.set_y_expand(true);

        menuItem.actor.add_child(icoBtn);
        menuItem.icoBtn = icoBtn;
        menuItem.deletePressId = icoBtn.connect('button-press-event',
            Lang.bind(this, function () {
                this._removeEntry(menuItem);
            })
        );

        this.historySection.addMenuItem(menuItem, 0);

        if (autoSelect === true)
            this._selectMenuItem(menuItem, autoSetClip);

        this._updateCache();
    },

    _removeAll: function () {
        let that = this;
        // We can't actually remove all items, because the clipboard still
        // has data that will be re-captured on next refresh, so we remove
        // all except the currently selected item
        that.historySection._getMenuItems().forEach(function (mItem) {
            if (!mItem.currentlySelected) {
                let idx = that.clipItemsRadioGroup.indexOf(mItem);
                mItem.destroy();
                that.clipItemsRadioGroup.splice(idx,1);
            }
        });
        that._updateCache();
        that._showNotification(_("Clipboard history cleared"));
    },

    _removeEntry: function (menuItem) {
        let itemIdx = this.clipItemsRadioGroup.indexOf(menuItem);

        menuItem.destroy();
        this.clipItemsRadioGroup.splice(itemIdx,1);
        this._updateCache();
    },

    _removeOldestEntries: function () {
        let that = this;
        while (that.clipItemsRadioGroup.length > MAX_REGISTRY_LENGTH) {
            let oldest = that.clipItemsRadioGroup.shift();
            oldest.actor.disconnect(oldest.buttonPressId);
            oldest.destroy();
        }

        that._updateCache();
    },

    _onMenuItemSelected: function (autoSet) {
        var that = this;
        that.radioGroup.forEach(function (menuItem) {
            let clipContents = that.clipContents;

            if (menuItem === that && clipContents) {
                that.setOrnament(PopupMenu.Ornament.DOT);
                that.icoBtn.visible = false;
                that.currentlySelected = true;
                if (autoSet !== false)
                    Clipboard.set_text(CLIPBOARD_TYPE, clipContents);
            }
            else {
                menuItem.icoBtn.visible = true;
                menuItem.setOrnament(PopupMenu.Ornament.NONE);
                menuItem.currentlySelected = false;
            }
        });

        that.menu.close();
    },

    _selectMenuItem: function (menuItem, autoSet) {
        let fn = Lang.bind(menuItem, this._onMenuItemSelected);
        fn(autoSet);
    },

    _getCache: function (cb) {
        return readRegistry(cb);
    },

    _updateCache: function () {
        writeRegistry(this.clipItemsRadioGroup.map(function (menuItem) {
            return menuItem.clipContents;
        }));
    },

    _refreshIndicator: function () {
        if (PRIVATEMODE) return; // Private mode, do not.

        let that = this;

        Clipboard.get_text(CLIPBOARD_TYPE, function (clipBoard, text) {
            let registry = that.clipItemsRadioGroup.map(function (menuItem) {
                return menuItem.clipContents;
            });

            if (text && registry.indexOf(text) < 0) {
                that._addEntry(text, true, false);
                that._removeOldestEntries();
            }
        });
    },

    _setupTimeout: function (reiterate) {
        let that = this;
        reiterate = typeof reiterate === 'boolean' ? reiterate : true;

        this._clipboardTimeoutId = Mainloop.timeout_add(TIMEOUT_MS, function () {
            that._refreshIndicator();

            // If the timeout handler returns `false`, the source is
            // automatically removed, so we reset the timeout-id so it won't
            // be removed on `.destroy()`
            if (reiterate === false)
                that._clipboardTimeoutId = null;

            // As long as the timeout handler returns `true`, the handler
            // will be invoked again and again as an interval
            return reiterate;
        });
    },

    _openSettings: function () {
        Util.spawn([
            "gnome-shell-extension-prefs",
            Me.uuid
        ]);
    },

   _showNotification: function (message) {
        if (this._notifSource == null) {
            this._notifSource = new MessageTray.Source('ClipboardIndicator', 'dialog-information-symbolic');
        }
        Main.messageTray.add(this._notifSource);
        let notification = null;
        if (this._notifSource.notifications.length == 0) {
            notification = new MessageTray.Notification(this._notifSource, message);
        } else {
            notification = this._notifSource.notifications[0];
            notification.update(message, { clear: true });
        }
        notification.setTransient(false);
        this._notifSource.notify(notification);
    },

    _createHistoryLabel: function () {
        this._historyLabel = new St.Label({
            style_class: 'ci-notification-label',
            text: ''
        });

        global.stage.add_actor(this._historyLabel);

        this._historyLabel.hide();
    },

    _onPrivateModeSwitch: function() {
        PRIVATEMODE = this.privateModeMenuItem.state;
        // We hide the history in private mode because it will be out of sync (selected item will not reflect clipboard)
        this.scrollViewMenuSection.actor.visible = !PRIVATEMODE;

        // If we get out of private mode then we restore the clipboard to old state
        if (!PRIVATEMODE) {
            let selectList = this.clipItemsRadioGroup.filter((item) => !!item.currentlySelected);

            if (selectList.length) {
                this._selectMenuItem(selectList[0]);
            } else {
                // Nothing to return to, let's empty it instead
                Clipboard.set_text(CLIPBOARD_TYPE, "");
            }

            this.icon.remove_style_class_name('private-mode');
        } else {
            this.icon.add_style_class_name('private-mode');
        }
    },

    _loadSettings: function () {
        this._settings = Prefs.SettingsSchema;
        this._settingsChangedId = this._settings.connect('changed',
            Lang.bind(this, this._onSettingsChange));

        this._fetchSettings();

        if (ENABLE_KEYBINDING)
            this._bindShortcuts();
    },

    _fetchSettings: function () {
        TIMEOUT_MS           = this._settings.get_int(Prefs.Fields.INTERVAL);
        MAX_REGISTRY_LENGTH  = this._settings.get_int(Prefs.Fields.HISTORY_SIZE);
        MAX_ENTRY_LENGTH     = this._settings.get_int(Prefs.Fields.PREVIEW_SIZE);
        DELETE_ENABLED       = this._settings.get_boolean(Prefs.Fields.DELETE);
        ENABLE_KEYBINDING    = this._settings.get_boolean(Prefs.Fields.ENABLE_KEYBINDING);
    },

    _onSettingsChange: function () {
        var that = this;

        // Load the settings into variables
        that._fetchSettings();

        // Remove old entries in case the registry size changed
        that._removeOldestEntries();

        // Re-set menu-items lables in case preview size changed
        that.historySection._getMenuItems().forEach(function (mItem) {
            that._setEntryLabel(mItem);
        });

        // Bind or unbind shortcuts
        if (ENABLE_KEYBINDING)
            that._bindShortcuts();
        else
            that._unbindShortcuts();
    },

    _bindShortcuts: function () {
        this._unbindShortcuts();
        this._bindShortcut(SETTING_KEY_CLEAR_HISTORY, this._removeAll);
        this._bindShortcut(SETTING_KEY_PREV_ENTRY, this._previousEntry);
        this._bindShortcut(SETTING_KEY_NEXT_ENTRY, this._nextEntry);
        this._bindShortcut(SETTING_KEY_TOGGLE_MENU, this._toggleMenu);
    },

    _unbindShortcuts: function () {
        this._shortcutsBindingIds.forEach(
            (id) => Main.wm.removeKeybinding(id)
        );

        this._shortcutsBindingIds = [];
    },

    _bindShortcut: function(name, cb) {
        var ModeType = Shell.hasOwnProperty('ActionMode') ?
            Shell.ActionMode : Shell.KeyBindingMode;

        Main.wm.addKeybinding(
            name,
            this._settings,
            Meta.KeyBindingFlags.NONE,
            ModeType.ALL,
            Lang.bind(this, cb)
        );

        this._shortcutsBindingIds.push(name);
    },

    _disconnectSettings: function () {
        if (!this._settingsChangedId)
            return;

        this._settings.disconnect(this._settingsChangedId);
        this._settingsChangedId = null;
    },

    _clearClipboardTimeout: function () {
        if (!this._clipboardTimeoutId)
            return;

        Mainloop.source_remove(this._clipboardTimeoutId);
        this._clipboardTimeoutId = null;
    },

    _clearLabelTimeout: function () {
        if (!this._historyLabelTimeoutId)
            return;

        Mainloop.source_remove(this._historyLabelTimeoutId);
        this._historyLabelTimeoutId = null;
    },

    _previousEntry: function() {
        let that = this;

        this.historySection._getMenuItems().some(function (mItem, i, menuItems){
            if (mItem.currentlySelected) {
                i--;                                 //get the previous index
                if (i < 0) i = menuItems.length - 1; //cycle if out of bound
                that._selectMenuItem(menuItems[i]);  //select the item
                let index = i + 1;                   //index to be displayed
                that._showNotification(index + ' / ' + menuItems.length + ': ' + menuItems[i].label.text);
                return true;
            }
            return false;
        });
    },

    _nextEntry: function() {
        let that = this;

        this.historySection._getMenuItems().some(function (mItem, i, menuItems) {
            if (mItem.currentlySelected) {
                i++;                                 //get the next index
                if (i === menuItems.length) i = 0;   //cycle if out of bound
                that._selectMenuItem(menuItems[i]);  //select the item
                let index = i + 1;                     //index to be displayed
                that._showNotification(index + ' / ' + menuItems.length + ': ' + menuItems[i].label.text);
                return true;
            }
            return false;
        });
    },

    _toggleMenu:function(){
        if(this.menu.visible)
            this.menu.close();
        else
            this.menu.open();
    }
});

function init () {
    let localeDir = Me.dir.get_child('locale');
    Gettext.bindtextdomain('clipboard-indicator', localeDir.get_path());
}

let clipboardIndicator;
function enable () {
    clipboardIndicator = new ClipboardIndicator();
    Main.panel.addToStatusArea('clipboardIndicator', clipboardIndicator, 1);
}

function disable () {
    clipboardIndicator.destroy();
}
<commit_msg>Forgot to import MessageTray<commit_after>const Clutter    = imports.gi.Clutter;
const Gio        = imports.gi.Gio;
const Lang       = imports.lang;
const Mainloop   = imports.mainloop;
const Meta       = imports.gi.Meta;
const Shell      = imports.gi.Shell;
const St         = imports.gi.St;
const PolicyType = imports.gi.Gtk.PolicyType;
const Util       = imports.misc.util;
const MessageTray = imports.ui.messageTray;

const Main      = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const CheckBox  = imports.ui.checkBox.CheckBox;

const Gettext = imports.gettext;
const _ = Gettext.domain('clipboard-indicator').gettext;

const Clipboard = St.Clipboard.get_default();
const CLIPBOARD_TYPE = St.ClipboardType.CLIPBOARD;

const SETTING_KEY_CLEAR_HISTORY = "clear-history";
const SETTING_KEY_PREV_ENTRY = "prev-entry";
const SETTING_KEY_NEXT_ENTRY = "next-entry";
const SETTING_KEY_TOGGLE_MENU = "toggle-menu";

const ExtensionUtils = imports.misc.extensionUtils;
const Me = ExtensionUtils.getCurrentExtension();
const Utils = Me.imports.utils;
const Prefs = Me.imports.prefs;
const prettyPrint = Utils.prettyPrint;
const writeRegistry = Utils.writeRegistry;
const readRegistry = Utils.readRegistry;

let TIMEOUT_MS           = 1000;
let MAX_REGISTRY_LENGTH  = 15;
let MAX_ENTRY_LENGTH     = 50;
let DELETE_ENABLED       = true;
let ENABLE_KEYBINDING    = true;
let PRIVATEMODE          = false;

const ClipboardIndicator = Lang.Class({
    Name: 'ClipboardIndicator',
    Extends: PanelMenu.Button,

    _settingsChangedId: null,
    _clipboardTimeoutId: null,
    _historyLabelTimeoutId: null,
    _historyLabel: null,
    _shortcutsBindingIds: [],
    clipItemsRadioGroup: [],

    destroy: function () {
        this._disconnectSettings();
        this._unbindShortcuts();
        this._clearClipboardTimeout();
        this._clearLabelTimeout();

        // Call parent
        this.parent();
    },

    _init: function() {
        this.parent(0.0, "ClipboardIndicator");
        let hbox = new St.BoxLayout({ style_class: 'panel-status-menu-box clipboard-indicator-hbox' });
        this.icon = new St.Icon({ icon_name: 'edit-paste-symbolic',
            style_class: 'system-status-icon clipboard-indicator-icon' });

        hbox.add_child(this.icon);
        this.actor.add_child(hbox);

        this._createHistoryLabel();
        this._loadSettings();
        this._buildMenu();
        this._setupTimeout();
    },

    _buildMenu: function () {
        let that = this;
        this._getCache(function (clipHistory) {
            let lastIdx = clipHistory.length - 1;
            let clipItemsArr = that.clipItemsRadioGroup;

            // Create menu section for items
            that.historySection = new PopupMenu.PopupMenuSection();

            that.scrollViewMenuSection = new PopupMenu.PopupMenuSection();
            let historyScrollView = new St.ScrollView({
                style_class: 'ci-history-menu-section',
                overlay_scrollbars: true
            });
            historyScrollView.add_actor(that.historySection.actor);

            that.scrollViewMenuSection.actor.add_actor(historyScrollView);

            that.menu.addMenuItem(that.scrollViewMenuSection);

            // Add cached items
            clipHistory.forEach(function (buffer) {
                that._addEntry(buffer);
            });

            // Add separator
            that.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());

            // Private mode switch
            that.privateModeMenuItem = new PopupMenu.PopupSwitchMenuItem(_("Private mode"), PRIVATEMODE, { reactive: true });
            that.privateModeMenuItem.connect('toggled', Lang.bind(that, that._onPrivateModeSwitch));
            that.menu.addMenuItem(that.privateModeMenuItem);

            // Add 'Clear' button which removes all items from cache
            let clearMenuItem = new PopupMenu.PopupMenuItem(_('Clear history'));
            that.menu.addMenuItem(clearMenuItem);
            clearMenuItem.connect('activate', Lang.bind(that, that._removeAll));

            // Add 'Settings' menu item to open settings
            let settingsMenuItem = new PopupMenu.PopupMenuItem(_('Settings'));
            that.menu.addMenuItem(settingsMenuItem);
            settingsMenuItem.connect('activate', Lang.bind(that, that._openSettings));

            if (lastIdx >= 0) {
                that._selectMenuItem(clipItemsArr[lastIdx]);
            }
        });
    },

    _setEntryLabel: function (menuItem) {
        let buffer = menuItem.clipContents,
        shortened = buffer.substr(0,MAX_ENTRY_LENGTH).replace(/\s+/g, ' ');

        if (buffer.length > MAX_ENTRY_LENGTH)
            shortened += '...';

        menuItem.label.set_text(shortened);
    },

    _addEntry: function (buffer, autoSelect, autoSetClip) {
        let menuItem = new PopupMenu.PopupMenuItem('');

        menuItem.menu = this.menu;
        menuItem.clipContents = buffer;
        menuItem.radioGroup = this.clipItemsRadioGroup;
        menuItem.buttonPressId = menuItem.connect('activate',
            Lang.bind(menuItem, this._onMenuItemSelected));

        this._setEntryLabel(menuItem);
        this.clipItemsRadioGroup.push(menuItem);

        let icon = new St.Icon({
            icon_name: 'edit-delete-symbolic', //'mail-attachment-symbolic',
            style_class: 'system-status-icon'
        });

        let icoBtn = new St.Button({
            style_class: 'ci-action-btn',
            x_fill: true,
            can_focus: true,
            child: icon
        });

        icoBtn.set_x_align(Clutter.ActorAlign.END);
        icoBtn.set_x_expand(true);
        icoBtn.set_y_expand(true);

        menuItem.actor.add_child(icoBtn);
        menuItem.icoBtn = icoBtn;
        menuItem.deletePressId = icoBtn.connect('button-press-event',
            Lang.bind(this, function () {
                this._removeEntry(menuItem);
            })
        );

        this.historySection.addMenuItem(menuItem, 0);

        if (autoSelect === true)
            this._selectMenuItem(menuItem, autoSetClip);

        this._updateCache();
    },

    _removeAll: function () {
        let that = this;
        // We can't actually remove all items, because the clipboard still
        // has data that will be re-captured on next refresh, so we remove
        // all except the currently selected item
        that.historySection._getMenuItems().forEach(function (mItem) {
            if (!mItem.currentlySelected) {
                let idx = that.clipItemsRadioGroup.indexOf(mItem);
                mItem.destroy();
                that.clipItemsRadioGroup.splice(idx,1);
            }
        });
        that._updateCache();
        that._showNotification(_("Clipboard history cleared"));
    },

    _removeEntry: function (menuItem) {
        let itemIdx = this.clipItemsRadioGroup.indexOf(menuItem);

        menuItem.destroy();
        this.clipItemsRadioGroup.splice(itemIdx,1);
        this._updateCache();
    },

    _removeOldestEntries: function () {
        let that = this;
        while (that.clipItemsRadioGroup.length > MAX_REGISTRY_LENGTH) {
            let oldest = that.clipItemsRadioGroup.shift();
            oldest.actor.disconnect(oldest.buttonPressId);
            oldest.destroy();
        }

        that._updateCache();
    },

    _onMenuItemSelected: function (autoSet) {
        var that = this;
        that.radioGroup.forEach(function (menuItem) {
            let clipContents = that.clipContents;

            if (menuItem === that && clipContents) {
                that.setOrnament(PopupMenu.Ornament.DOT);
                that.icoBtn.visible = false;
                that.currentlySelected = true;
                if (autoSet !== false)
                    Clipboard.set_text(CLIPBOARD_TYPE, clipContents);
            }
            else {
                menuItem.icoBtn.visible = true;
                menuItem.setOrnament(PopupMenu.Ornament.NONE);
                menuItem.currentlySelected = false;
            }
        });

        that.menu.close();
    },

    _selectMenuItem: function (menuItem, autoSet) {
        let fn = Lang.bind(menuItem, this._onMenuItemSelected);
        fn(autoSet);
    },

    _getCache: function (cb) {
        return readRegistry(cb);
    },

    _updateCache: function () {
        writeRegistry(this.clipItemsRadioGroup.map(function (menuItem) {
            return menuItem.clipContents;
        }));
    },

    _refreshIndicator: function () {
        if (PRIVATEMODE) return; // Private mode, do not.

        let that = this;

        Clipboard.get_text(CLIPBOARD_TYPE, function (clipBoard, text) {
            let registry = that.clipItemsRadioGroup.map(function (menuItem) {
                return menuItem.clipContents;
            });

            if (text && registry.indexOf(text) < 0) {
                that._addEntry(text, true, false);
                that._removeOldestEntries();
            }
        });
    },

    _setupTimeout: function (reiterate) {
        let that = this;
        reiterate = typeof reiterate === 'boolean' ? reiterate : true;

        this._clipboardTimeoutId = Mainloop.timeout_add(TIMEOUT_MS, function () {
            that._refreshIndicator();

            // If the timeout handler returns `false`, the source is
            // automatically removed, so we reset the timeout-id so it won't
            // be removed on `.destroy()`
            if (reiterate === false)
                that._clipboardTimeoutId = null;

            // As long as the timeout handler returns `true`, the handler
            // will be invoked again and again as an interval
            return reiterate;
        });
    },

    _openSettings: function () {
        Util.spawn([
            "gnome-shell-extension-prefs",
            Me.uuid
        ]);
    },

   _showNotification: function (message) {
        if (this._notifSource == null) {
            this._notifSource = new MessageTray.Source('ClipboardIndicator', 'dialog-information-symbolic');
        }
        Main.messageTray.add(this._notifSource);
        let notification = null;
        if (this._notifSource.notifications.length == 0) {
            notification = new MessageTray.Notification(this._notifSource, message);
        } else {
            notification = this._notifSource.notifications[0];
            notification.update(message, { clear: true });
        }
        notification.setTransient(false);
        this._notifSource.notify(notification);
    },

    _createHistoryLabel: function () {
        this._historyLabel = new St.Label({
            style_class: 'ci-notification-label',
            text: ''
        });

        global.stage.add_actor(this._historyLabel);

        this._historyLabel.hide();
    },

    _onPrivateModeSwitch: function() {
        PRIVATEMODE = this.privateModeMenuItem.state;
        // We hide the history in private mode because it will be out of sync (selected item will not reflect clipboard)
        this.scrollViewMenuSection.actor.visible = !PRIVATEMODE;

        // If we get out of private mode then we restore the clipboard to old state
        if (!PRIVATEMODE) {
            let selectList = this.clipItemsRadioGroup.filter((item) => !!item.currentlySelected);

            if (selectList.length) {
                this._selectMenuItem(selectList[0]);
            } else {
                // Nothing to return to, let's empty it instead
                Clipboard.set_text(CLIPBOARD_TYPE, "");
            }

            this.icon.remove_style_class_name('private-mode');
        } else {
            this.icon.add_style_class_name('private-mode');
        }
    },

    _loadSettings: function () {
        this._settings = Prefs.SettingsSchema;
        this._settingsChangedId = this._settings.connect('changed',
            Lang.bind(this, this._onSettingsChange));

        this._fetchSettings();

        if (ENABLE_KEYBINDING)
            this._bindShortcuts();
    },

    _fetchSettings: function () {
        TIMEOUT_MS           = this._settings.get_int(Prefs.Fields.INTERVAL);
        MAX_REGISTRY_LENGTH  = this._settings.get_int(Prefs.Fields.HISTORY_SIZE);
        MAX_ENTRY_LENGTH     = this._settings.get_int(Prefs.Fields.PREVIEW_SIZE);
        DELETE_ENABLED       = this._settings.get_boolean(Prefs.Fields.DELETE);
        ENABLE_KEYBINDING    = this._settings.get_boolean(Prefs.Fields.ENABLE_KEYBINDING);
    },

    _onSettingsChange: function () {
        var that = this;

        // Load the settings into variables
        that._fetchSettings();

        // Remove old entries in case the registry size changed
        that._removeOldestEntries();

        // Re-set menu-items lables in case preview size changed
        that.historySection._getMenuItems().forEach(function (mItem) {
            that._setEntryLabel(mItem);
        });

        // Bind or unbind shortcuts
        if (ENABLE_KEYBINDING)
            that._bindShortcuts();
        else
            that._unbindShortcuts();
    },

    _bindShortcuts: function () {
        this._unbindShortcuts();
        this._bindShortcut(SETTING_KEY_CLEAR_HISTORY, this._removeAll);
        this._bindShortcut(SETTING_KEY_PREV_ENTRY, this._previousEntry);
        this._bindShortcut(SETTING_KEY_NEXT_ENTRY, this._nextEntry);
        this._bindShortcut(SETTING_KEY_TOGGLE_MENU, this._toggleMenu);
    },

    _unbindShortcuts: function () {
        this._shortcutsBindingIds.forEach(
            (id) => Main.wm.removeKeybinding(id)
        );

        this._shortcutsBindingIds = [];
    },

    _bindShortcut: function(name, cb) {
        var ModeType = Shell.hasOwnProperty('ActionMode') ?
            Shell.ActionMode : Shell.KeyBindingMode;

        Main.wm.addKeybinding(
            name,
            this._settings,
            Meta.KeyBindingFlags.NONE,
            ModeType.ALL,
            Lang.bind(this, cb)
        );

        this._shortcutsBindingIds.push(name);
    },

    _disconnectSettings: function () {
        if (!this._settingsChangedId)
            return;

        this._settings.disconnect(this._settingsChangedId);
        this._settingsChangedId = null;
    },

    _clearClipboardTimeout: function () {
        if (!this._clipboardTimeoutId)
            return;

        Mainloop.source_remove(this._clipboardTimeoutId);
        this._clipboardTimeoutId = null;
    },

    _clearLabelTimeout: function () {
        if (!this._historyLabelTimeoutId)
            return;

        Mainloop.source_remove(this._historyLabelTimeoutId);
        this._historyLabelTimeoutId = null;
    },

    _previousEntry: function() {
        let that = this;

        this.historySection._getMenuItems().some(function (mItem, i, menuItems){
            if (mItem.currentlySelected) {
                i--;                                 //get the previous index
                if (i < 0) i = menuItems.length - 1; //cycle if out of bound
                that._selectMenuItem(menuItems[i]);  //select the item
                let index = i + 1;                   //index to be displayed
                that._showNotification(index + ' / ' + menuItems.length + ': ' + menuItems[i].label.text);
                return true;
            }
            return false;
        });
    },

    _nextEntry: function() {
        let that = this;

        this.historySection._getMenuItems().some(function (mItem, i, menuItems) {
            if (mItem.currentlySelected) {
                i++;                                 //get the next index
                if (i === menuItems.length) i = 0;   //cycle if out of bound
                that._selectMenuItem(menuItems[i]);  //select the item
                let index = i + 1;                     //index to be displayed
                that._showNotification(index + ' / ' + menuItems.length + ': ' + menuItems[i].label.text);
                return true;
            }
            return false;
        });
    },

    _toggleMenu:function(){
        if(this.menu.visible)
            this.menu.close();
        else
            this.menu.open();
    }
});

function init () {
    let localeDir = Me.dir.get_child('locale');
    Gettext.bindtextdomain('clipboard-indicator', localeDir.get_path());
}

let clipboardIndicator;
function enable () {
    clipboardIndicator = new ClipboardIndicator();
    Main.panel.addToStatusArea('clipboardIndicator', clipboardIndicator, 1);
}

function disable () {
    clipboardIndicator.destroy();
}
<|endoftext|>


<commit_before>define([
    '/common/cryptget.js',
    '/common/userObject.js',
    '/common/common-hash.js',
    '/common/common-realtime.js',
], function (Crypt, FO, Hash, Realtime) {
    var exp = {};

    exp.anonDriveIntoUser = function (proxyData, fsHash, cb) {
        // Make sure we have an FS_hash and we don't use it, otherwise just stop the migration and cb
        if (!fsHash || !proxyData.loggedIn) {
            if (typeof(cb) === "function") { return void cb(); }
        }
        // Get the content of FS_hash and then merge the objects, remove the migration key and cb
        var todo = function (err, doc) {
            if (err) { console.error("Cannot migrate recent pads", err); return; }
            var parsed;
            if (!doc) {
                if (typeof(cb) === "function") { cb(); }
                return;
            }
            try { parsed = JSON.parse(doc); } catch (e) {
                if (typeof(cb) === "function") { cb(); }
                console.error("Cannot parsed recent pads", e);
                return;
            }
            if (parsed) {
                var proxy = proxyData.proxy;
                var oldFo = FO.init(parsed.drive, {
                    loggedIn: true,
                    outer: true
                });
                var onMigrated = function () {
                    oldFo.fixFiles(true);
                    var manager = proxyData.manager;
                    var oldFiles = oldFo.getFiles([oldFo.FILES_DATA]);
                    oldFiles.forEach(function (id) {
                        var data = oldFo.getFileData(id);
                        var channel = data.channel;

                        var datas = manager.findChannel(channel, true);
                        // Do not migrate a pad if we already have it, it would create a duplicate
                        // in the drive
                        if (datas.length !== 0) {
                            // We want to merge a read-only pad: it can't be stronger than what
                            // we already have so abort
                            if (!data.href) { return; }

                            // We want to merge an edit pad: check if we have the same channel
                            // but read-only and upgrade it in that case
                            datas.forEach(function (pad) {
                                if (!pad.href) { data.href = pad.href; }
                            });
                            return;
                        }
                        // Here it means we have a new href, so we should add it to the drive
                        if (data) {
                            manager.addPad(null, data, function (err) {
                                if (err) {
                                    return void console.error("Cannot import file:", data, err);
                                }
                            });
                        }
                    });
                    if (!proxy.FS_hashes || !Array.isArray(proxy.FS_hashes)) {
                        proxy.FS_hashes = [];
                    }
                    proxy.FS_hashes.push(fsHash);
                    if (typeof(cb) === "function") {
                        Realtime.whenRealtimeSyncs(proxyData.realtime, cb);
                    }
                };
                oldFo.migrate(onMigrated);
                return;
            }
            if (typeof(cb) === "function") { cb(); }
        };
        Crypt.get(fsHash, todo);
    };

    return exp;
});
<commit_msg>safety net for call of undefined function in mergeDrive<commit_after>define([
    '/common/cryptget.js',
    '/common/userObject.js',
    '/common/common-hash.js',
    '/common/common-realtime.js',
], function (Crypt, FO, Hash, Realtime) {
    var exp = {};

    exp.anonDriveIntoUser = function (proxyData, fsHash, cb) {
        // Make sure we have an FS_hash and we don't use it, otherwise just stop the migration and cb
        if (!fsHash || !proxyData.loggedIn) {
            if (typeof(cb) === "function") { return void cb(); }
        }
        // Get the content of FS_hash and then merge the objects, remove the migration key and cb
        var todo = function (err, doc) {
            if (err) { console.error("Cannot migrate recent pads", err); return; }
            var parsed;
            if (!doc) {
                if (typeof(cb) === "function") { cb(); }
                return;
            }
            try { parsed = JSON.parse(doc); } catch (e) {
                if (typeof(cb) === "function") { cb(); }
                console.error("Cannot parsed recent pads", e);
                return;
            }
            if (parsed) {
                var proxy = proxyData.proxy;
                var oldFo = FO.init(parsed.drive, {
                    loggedIn: true,
                    outer: true
                });
                var onMigrated = function () {
                    oldFo.fixFiles(true);
                    var manager = proxyData.manager;
                    var oldFiles = oldFo.getFiles([oldFo.FILES_DATA]);
                    oldFiles.forEach(function (id) {
                        var data = oldFo.getFileData(id);
                        var channel = data.channel;

                        var datas = manager.findChannel(channel, true);
                        // Do not migrate a pad if we already have it, it would create a duplicate
                        // in the drive
                        if (datas.length !== 0) {
                            // We want to merge a read-only pad: it can't be stronger than what
                            // we already have so abort
                            if (!data.href) { return; }

                            // We want to merge an edit pad: check if we have the same channel
                            // but read-only and upgrade it in that case
                            datas.forEach(function (pad) {
                                if (!pad.href) { data.href = pad.href; }
                            });
                            return;
                        }
                        // Here it means we have a new href, so we should add it to the drive
                        if (data) {
                            manager.addPad(null, data, function (err) {
                                if (err) {
                                    return void console.error("Cannot import file:", data, err);
                                }
                            });
                        }
                    });
                    if (!proxy.FS_hashes || !Array.isArray(proxy.FS_hashes)) {
                        proxy.FS_hashes = [];
                    }
                    proxy.FS_hashes.push(fsHash);
                    if (typeof(cb) === "function") {
                        Realtime.whenRealtimeSyncs(proxyData.realtime, cb);
                    }
                };
                if (oldFo && typeof(oldFo.migrate) === 'function') {
                    oldFo.migrate(onMigrated);
                } else {
                    console.log('oldFo.migrate is not a function');
                    onMigrated();
                }
                return;
            }
            if (typeof(cb) === "function") { cb(); }
        };
        Crypt.get(fsHash, todo);
    };

    return exp;
});
<|endoftext|>


<commit_before>/** Version: 0.7.1 **/
/**
 * Copyright 2008 Toomas Rmer
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
**/
/*
	Representation of the PGN format. Different meta information
	about the actual game(s) plus the moves and result of the game.
*/
function Pgn(pgn) {
	// properties of the game eg players, ELOs etc
	this.props = new Object();
	this.requiredProps = ['Result','Black','White','Date',
								'Round','Site','Event'];
	this.requiredLength = this.requiredProps.length;
	// the moves, one move contains the black and white move
	this.moves = new Array();
	// the current move in the game
	this.currentMove = 0;
	// for outputting white and black moves separately
	this.skip = 0;

	// strip newlines
	this.pgnOrig = pgn;
	pgn = pgn.replace(/\n/g," ");

	// replace dollar signs
	//"!", "?", "!!", "!?", "?!", and "??"
	pgn = pgn.replace(/\ \$1[0-9]*/g, "!");
	pgn = pgn.replace(/\ \$2[0-9]*/g, "?");
	pgn = pgn.replace(/\ \$3[0-9]*/g, "!!");
	pgn = pgn.replace(/\ \$4[0-9]*/g, "??");
	pgn = pgn.replace(/\ \$5[0-9]*/g, "!?");
	pgn = pgn.replace(/\ \$6[0-9]*/g, "?!");
	pgn = pgn.replace(/\ \$[0-9]+/g, "");

	// make double spaces to single spaces
	pgn = pgn.replace(/\s+/g,' ');

	this.pgn = pgn;
	this.pgnRaw = pgn;
	if (this.isBroken(pgn))
		this.pgnStripped = this.stripItBroken(pgn);
	else
		this.pgnStripped = this.stripIt(pgn);

	/* constructor */

	// strip comments
	if (this.isBroken(pgn))
		this.pgn = this.stripItBroken(pgn,true);
	else
		this.pgn = this.stripIt(pgn,true);

	// Match all properties
	var reprop = /\[([^\]]*)\]/gi;
	var matches = this.pgn.match(reprop);
	if (matches) {
		// extract information from each matched property
		 for(var i = 0;i < matches.length; i++) {
			 // lose the brackets
			 tmpMatches = matches[i].substring(1, matches[i].length-1);
			 // split by the first space
			 var key = tmpMatches.substring(0, tmpMatches.indexOf(" "));
			 var value = tmpMatches.substring(tmpMatches.indexOf(" ")+1);
			 if (value.charAt(0) == '"')
				 value = value.substr(1);
			 if (value.charAt(value.length-1) == '"')
				 value = value.substr(0, value.length-1);

			 this.props[key] = value;
			 this.pgn = this.pgn.replace(matches[i], "");
		 }
	}
	length = this.requiredLength;
	while(length--) {
		if(!this.props[this.requiredProps[length]])
			this.props[this.requiredProps[length]] = "?";
	}
	// remove the properties
	this.pgn = this.pgn.replace(/\[[^\]]*\]/g,'');
	//trim
	this.pgn = this.pgn.replace(/^\s+|\s+$/g, '');

	var gameOverre = new Array(
		/1\/2-1\/2/,
		/0-1/,
		/1-0/,
		/\*/
	);

	// the moves;
	var themoves = this.pgn.split(" ");
	var tmp = new Array();
	tmp[1] = null;
	var tmpidx = 0;	//make this 1 if FEN and black to move
	if (this.props["FEN"]) {
		var fen = this.props['FEN'].split(/\/| /g);
		if (fen[8] == 'b') {
			tmpidx = 1;
			this.skip = 1;
		}
	}

	if (themoves.length>0 && themoves[themoves.length-1] == "...") {
		 themoves = themoves.slice(0, themoves.length-1);
	}

	var sizeOfTheMoves = themoves.length;
	if (themoves.length>0) {
		for (var i=0;i<gameOverre.length;i++) {
			if (themoves[themoves.length-1].match(gameOverre[i])) {
				sizeOfTheMoves = themoves.length-1;
				continue;
			}
		}
	}

	for (var i=0;i<sizeOfTheMoves;i++) {	//don't handle game end bit
		if (themoves[i]) {
			themoves[i] = themoves[i].replace(/^\s+|\s+$/g, '');
		}

		if (!themoves[i]) {
			continue;
		}

		if (themoves[i].indexOf("-") != -1
			 && !/[0|o]-[0|o]/i.test(themoves[i])
			 && !/[0|o]-[0|o]-[0|o]/i.test(themoves[i])
			) {
			var tmp2 = themoves[i].split("-");
			var matches = tmp2[0].match(/[0-9]*?\.?([A-Z])/);
			var newMove;
			if (matches != null) {
				 // we can just replace the - with nothing
				 newMove  = themoves[i].replace("-","");
			}
			else {
				matches = tmp2[0].match(/[0-9]+\./);
				if (matches) {
					newMove = matches[0]+tmp2[1];
				}
				else {
					newMove = tmp2[1];
				}
			}
			themoves[i] = newMove;
		}
		var c = themoves[i].charAt(0);
		if (c >= '1' && c <= '9') {	//move number
			c = themoves[i].charAt(themoves[i].length-1);
			if (c == '.') {	//ends with . so nothing but a move
				continue;
			}
			var found = false;
			for (var j=0;j<themoves[i].length;j++) {
				c = themoves[i].charAt(j);
				if (c >= '0' && c <= '9') {
					continue;
				}
				else {
					found = true;
					var idx = j;
					// 6.0-0 goes wrong as 0 is used for castling
					if (!(themoves[i].charAt(j) >= '0' && themoves[i].charAt(j)<='9')) {
						 idx = j+1;
				}
					themoves[i] = themoves[i].substring(idx);	//strip move number
					break;
				}
			}
			if (!found) {
				continue;
			}
		}
		tmp[tmpidx] = themoves[i];
		if (tmpidx == 1) {	//black's move or last move
			var move = new Move(tmp[0], tmp[1]);
			this.moves[this.moves.length] = move;
			tmpidx = 0;
			tmp = new Array();
			tmp[1] = null;
		}
		else {
			tmpidx = 1;
		}
	}

	if (tmp[0] || tmp[1]) {
		var move = new Move(tmp[0], tmp[1]);
		this.moves[this.moves.length] = move;
	}
}

Pgn.prototype.nextMove = function() {
		var rtrn = null;
		try{
			if (this.skip) {
				this.skip = 0;
				rtrn = new Array(this.moves[this.currentMove].black,
													'black');
				this.currentMove++;
			}
			else {
				this.skip = 1;
				rtrn = new Array(this.moves[this.currentMove].white,
											'white');
			}

			if (rtrn[0] == null || rtrn[0].length == 0)
				rtrn = null;
			return rtrn;
		}
		catch (e) {
			return null;
		}
	};

Pgn.prototype.getComment = function(move, idx) {
		var i = this.pgnStripped.indexOf(move,idx);
		if (i == -1) {
			//throw("getComment error, could not find move '"
			//				+move+"'"+", with index '"+idx+"'");
			return [null,idx];
		}

		for (var j=i+move.length;j<this.pgnStripped.length;j++) {
			var c = this.pgnStripped.charAt(j);
			switch (c) {
				case ' ':
					break;
				case '_':	//found comment
					for (var k=j;k<this.pgnStripped.length;k++) {
						var c2 = this.pgnStripped.charAt(k);
						switch (c2) {
							case '_':	//found comment
								break;
							default:	//no comment
								// we might have many comments separated with spaces
								// as we strip all double spaces to single ones we
								// can just check for the next char being '_'
								if (this.pgnStripped.length>k+1
									 	&& this.pgnStripped.charAt(k+1) == '_') {
									continue;
								}
								return [this.pgnRaw.substring(j,k),k];
						}
					}
					break;
				default:	//no comment
					return [null,idx];
			}
		}
		return [null,idx];
	};

Pgn.prototype.isBroken = function (val) {
		var pCount = 0;
		var cCount = 0;
		var lastOne = "";
		var inComment = false;
		for (var i=0;i<val.length;i++) {
			var c = val.charAt(i);
			if(inComment) {
				switch (c) {
					case '}':
						inComment = false;
						// closing a non-existent curly brace
						if (cCount == 0)
							return true;
						// if we're closing a parenthesis instead of a curly
						if (lastOne == "p")
							return true;
						lastOne = "";
						cCount--;
						break;
					case '{':
						// Cannot nest comments
						return true;
				}
			} else {
				switch (c) {
					case '(':
						pCount++;
						lastOne = "p";
						break;
					case ')':
						// closing a non-existent curly brace
						if (pCount == 0)
							return true;
						// closing a curly instead of a parenthesis
						if (lastOne == "c")
							return true;
						lastOne = "";
						pCount--;
						break;
					case '{':
						inComment = true;
						cCount++;
						lastOne = "c";
						break;
				}
			}
		}
		return false;
	};

Pgn.prototype.stripItBroken = function (val, strip) {
	var count = 0;
	var out = new Array();
	/*
		At one point chesspastebin.com started getting cames
		with invalid PGNs, mostly in the form
		{ comment comment ( something between starting brackets}.
		As you can see, the ( is not closed.
		isOpen and isCurlyO are just for that to take normal
		guesses in that kind of situations.
	*/
	var isOpen = false;
	var isCurlyO = false;
	var curlyOpenedFst = false;
	for (var i=0;i<val.length;i++) {
		var c = val.charAt(i);
		switch (c) {
			case '(':
				if (!strip) {
					out[out.length] = '_';
				}
				count++;
				if (isOpen) {
					 	count--;
				}
				isOpen = true;
				break;
			case '{':
				isCurlyO = true;
				if (!strip) {
					out[out.length] = '_';
				}
				count++;
				if (!isOpen)
					 curlyOpenedFst=true;
				break;
			case '}':
				if (isOpen && isCurlyO && curlyOpenedFst) {
					// lets close the open (
					count--;
					isOpen = false;
				}
				isCurlyO = false;
				curlyOpenedFst = false;
				count--;
				if (!strip) {
					out[out.length] = '_';
				}
				break;
			case ')':
				if (isOpen) {
					 count--;
					 if (!strip) {
						 out[out.length] = '_';
					 }
					 isOpen = false;
				}
				break;
			case '\t':
				out[out.length] = ' ';
				break;
			default:
				if (count > 0) {
					if (!strip) {
						out[out.length] = '_';
					}
				}
				else {
					out[out.length] = c;
				}
		}
	}
	return out.join("");
};

/*
	Strip game comments from a PGN string. If second
	parameter set false true then comments will be replaced
	by an underscore.
*/
Pgn.prototype.stripIt = function (val, strip) {
	var count = 0;
	var out = new Array();
	var inComment = false;
	for (var i=0;i<val.length;i++) {
		var c = val.charAt(i);
		switch (c) {
			case '(':
				if (!strip) {
					out[out.length] = '_';
				}
				if(!inComment) {
					count++;
				}
				break;
			case '{':
				inComment = true;
				if (!strip) {
					out[out.length] = '_';
				}
				count++;
				break;
			case '}':
				count--;
				if (!strip) {
					out[out.length] = '_';
				}
				inComment = false;
				break;
			case ')':
				if(!inComment) {
					count--;
				}
				if (!strip) {
					out[out.length] = '_';
				}
				break;
			case '\t':
				out[out.length] = ' ';
				break;
			default:
				if (count > 0) {
					if (!strip) {
						out[out.length] = '_';
					}
				}
				else {
					out[out.length] = c;
				}
		}
	}
	return out.join("");
};
<commit_msg>Refactoring<commit_after>/** Version: 0.7.1 **/
/**
 * Copyright 2008 Toomas Rmer
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
**/
/*
	Representation of the PGN format. Different meta information
	about the actual game(s) plus the moves and result of the game.
*/
function Pgn(pgn) {
	// properties of the game eg players, ELOs etc
	this.props = new Object();
	this.requiredProps = ['Result','Black','White','Date',
								'Round','Site','Event'];
	this.requiredLength = this.requiredProps.length;
	// the moves, one move contains the black and white move
	this.moves = new Array();
	// the current move in the game
	this.currentMove = 0;
	// for outputting white and black moves separately
	this.skip = 0;

	// strip newlines
	this.pgnOrig = pgn;
	pgn = this.normalize(pgn);

	this.pgn = pgn;
	this.pgnRaw = pgn;
	if (this.isBroken(pgn))
		this.pgnStripped = this.stripItBroken(pgn);
	else
		this.pgnStripped = this.stripIt(pgn);

	this.pgn = this.extractTags(this.pgn);

	// strip comments
	if (this.isBroken(pgn))
		this.pgn = this.stripItBroken(this.pgn,true);
	else
		this.pgn = this.stripIt(this.pgn,true);

	var gameOverre = new Array(
		/1\/2-1\/2/,
		/0-1/,
		/1-0/,
		/\*/
	);

	// the moves;
	var themoves = this.pgn.split(" ");
	var tmp = new Array();
	tmp[1] = null;
	var tmpidx = 0;	//make this 1 if FEN and black to move
	if (this.props["FEN"]) {
		var fen = this.props['FEN'].split(/\/| /g);
		if (fen[8] == 'b') {
			tmpidx = 1;
			this.skip = 1;
		}
	}

	if (themoves.length>0 && themoves[themoves.length-1] == "...") {
		 themoves = themoves.slice(0, themoves.length-1);
	}

	var sizeOfTheMoves = themoves.length;
	if (themoves.length>0) {
		for (var i=0;i<gameOverre.length;i++) {
			if (themoves[themoves.length-1].match(gameOverre[i])) {
				sizeOfTheMoves = themoves.length-1;
				continue;
			}
		}
	}

	for (var i=0;i<sizeOfTheMoves;i++) {	//don't handle game end bit
		if (themoves[i]) {
			themoves[i] = themoves[i].replace(/^\s+|\s+$/g, '');
		}

		if (!themoves[i]) {
			continue;
		}

		if (themoves[i].indexOf("-") != -1
			 && !/[0|o]-[0|o]/i.test(themoves[i])
			 && !/[0|o]-[0|o]-[0|o]/i.test(themoves[i])
			) {
			var tmp2 = themoves[i].split("-");
			var matches = tmp2[0].match(/[0-9]*?\.?([A-Z])/);
			var newMove;
			if (matches != null) {
				 // we can just replace the - with nothing
				 newMove  = themoves[i].replace("-","");
			}
			else {
				matches = tmp2[0].match(/[0-9]+\./);
				if (matches) {
					newMove = matches[0]+tmp2[1];
				}
				else {
					newMove = tmp2[1];
				}
			}
			themoves[i] = newMove;
		}
		var c = themoves[i].charAt(0);
		if (c >= '1' && c <= '9') {	//move number
			c = themoves[i].charAt(themoves[i].length-1);
			if (c == '.') {	//ends with . so nothing but a move
				continue;
			}
			var found = false;
			for (var j=0;j<themoves[i].length;j++) {
				c = themoves[i].charAt(j);
				if (c >= '0' && c <= '9') {
					continue;
				}
				else {
					found = true;
					var idx = j;
					// 6.0-0 goes wrong as 0 is used for castling
					if (!(themoves[i].charAt(j) >= '0' && themoves[i].charAt(j)<='9')) {
						 idx = j+1;
				}
					themoves[i] = themoves[i].substring(idx);	//strip move number
					break;
				}
			}
			if (!found) {
				continue;
			}
		}
		tmp[tmpidx] = themoves[i];
		if (tmpidx == 1) {	//black's move or last move
			var move = new Move(tmp[0], tmp[1]);
			this.moves[this.moves.length] = move;
			tmpidx = 0;
			tmp = new Array();
			tmp[1] = null;
		}
		else {
			tmpidx = 1;
		}
	}

	if (tmp[0] || tmp[1]) {
		var move = new Move(tmp[0], tmp[1]);
		this.moves[this.moves.length] = move;
	}
}
/**
 *	This will "normalize" the pgn file by removing line breaks, collapsing strings of
 *	spaces, and replacing the symbols for moves with the characters (!, ?, etc.)
 */
Pgn.prototype.normalize = function(pgn) {
	pgn = pgn.replace(/\n/g," ");

	// replace dollar signs
	//"!", "?", "!!", "!?", "?!", and "??"
	pgn = pgn.replace(/\ \$1[0-9]*/g, "!");
	pgn = pgn.replace(/\ \$2[0-9]*/g, "?");
	pgn = pgn.replace(/\ \$3[0-9]*/g, "!!");
	pgn = pgn.replace(/\ \$4[0-9]*/g, "??");
	pgn = pgn.replace(/\ \$5[0-9]*/g, "!?");
	pgn = pgn.replace(/\ \$6[0-9]*/g, "?!");
	pgn = pgn.replace(/\ \$[0-9]+/g, "");

	// make double spaces to single spaces
	return pgn.replace(/\s+/g,' ');
}
/**
 *	This function takes a pgn game string and extracts all the tags into the class
 *	variable props as key/value pairs. it returns the pgn string, minus the tags.
 */
Pgn.prototype.extractTags = function (pgn) {
	var matches;
	var reprop = /\[([^\]]*)\]/gi;
	if (matches = pgn.match(reprop)) {
		// extract information from each matched property
		for(var i = 0;i < matches.length; i++) {
			// lose the brackets
			tmpMatches = matches[i].substring(1, matches[i].length-1);
			// split by the first space
			var key = tmpMatches.substring(0, tmpMatches.indexOf(" "));
			var value = tmpMatches.substring(tmpMatches.indexOf(" ")+1);
			if (value.charAt(0) == '"')
				value = value.substr(1);
			if (value.charAt(value.length-1) == '"')
				value = value.substr(0, value.length-1);

			this.props[key] = value;
			pgn = pgn.replace(matches[i], "");
		}
	}
	length = this.requiredLength;
	while(length--) {
		if(!this.props[this.requiredProps[length]])
			this.props[this.requiredProps[length]] = "?";
	}

	return pgn.replace(/\[[^\]]*\]/g,'').replace(/^\s+|\s+$/g, '');
}

Pgn.prototype.nextMove = function() {
		var rtrn = null;
		try{
			if (this.skip) {
				this.skip = 0;
				rtrn = new Array(this.moves[this.currentMove].black,
													'black');
				this.currentMove++;
			}
			else {
				this.skip = 1;
				rtrn = new Array(this.moves[this.currentMove].white,
											'white');
			}

			if (rtrn[0] == null || rtrn[0].length == 0)
				rtrn = null;
			return rtrn;
		}
		catch (e) {
			return null;
		}
	};

Pgn.prototype.getComment = function(move, idx) {
		var i = this.pgnStripped.indexOf(move,idx);
		if (i == -1) {
			//throw("getComment error, could not find move '"
			//				+move+"'"+", with index '"+idx+"'");
			return [null,idx];
		}

		for (var j=i+move.length;j<this.pgnStripped.length;j++) {
			var c = this.pgnStripped.charAt(j);
			switch (c) {
				case ' ':
					break;
				case '_':	//found comment
					for (var k=j;k<this.pgnStripped.length;k++) {
						var c2 = this.pgnStripped.charAt(k);
						switch (c2) {
							case '_':	//found comment
								break;
							default:	//no comment
								// we might have many comments separated with spaces
								// as we strip all double spaces to single ones we
								// can just check for the next char being '_'
								if (this.pgnStripped.length>k+1
									 	&& this.pgnStripped.charAt(k+1) == '_') {
									continue;
								}
								return [this.pgnRaw.substring(j,k),k];
						}
					}
					break;
				default:	//no comment
					return [null,idx];
			}
		}
		return [null,idx];
	};

Pgn.prototype.isBroken = function (val) {
		var pCount = 0;
		var cCount = 0;
		var lastOne = "";
		var inComment = false;
		for (var i=0;i<val.length;i++) {
			var c = val.charAt(i);
			if(inComment) {
				switch (c) {
					case '}':
						inComment = false;
						// closing a non-existent curly brace
						if (cCount == 0)
							return true;
						// if we're closing a parenthesis instead of a curly
						if (lastOne == "p")
							return true;
						lastOne = "";
						cCount--;
						break;
					case '{':
						// Cannot nest comments
						return true;
				}
			} else {
				switch (c) {
					case '(':
						pCount++;
						lastOne = "p";
						break;
					case ')':
						// closing a non-existent curly brace
						if (pCount == 0)
							return true;
						// closing a curly instead of a parenthesis
						if (lastOne == "c")
							return true;
						lastOne = "";
						pCount--;
						break;
					case '{':
						inComment = true;
						cCount++;
						lastOne = "c";
						break;
				}
			}
		}
		return false;
	};

Pgn.prototype.stripItBroken = function (val, strip) {
	var count = 0;
	var out = new Array();
	/*
		At one point chesspastebin.com started getting cames
		with invalid PGNs, mostly in the form
		{ comment comment ( something between starting brackets}.
		As you can see, the ( is not closed.
		isOpen and isCurlyO are just for that to take normal
		guesses in that kind of situations.
	*/
	var isOpen = false;
	var isCurlyO = false;
	var curlyOpenedFst = false;
	for (var i=0;i<val.length;i++) {
		var c = val.charAt(i);
		switch (c) {
			case '(':
				if (!strip) {
					out[out.length] = '_';
				}
				count++;
				if (isOpen) {
					 	count--;
				}
				isOpen = true;
				break;
			case '{':
				isCurlyO = true;
				if (!strip) {
					out[out.length] = '_';
				}
				count++;
				if (!isOpen)
					 curlyOpenedFst=true;
				break;
			case '}':
				if (isOpen && isCurlyO && curlyOpenedFst) {
					// lets close the open (
					count--;
					isOpen = false;
				}
				isCurlyO = false;
				curlyOpenedFst = false;
				count--;
				if (!strip) {
					out[out.length] = '_';
				}
				break;
			case ')':
				if (isOpen) {
					 count--;
					 if (!strip) {
						 out[out.length] = '_';
					 }
					 isOpen = false;
				}
				break;
			case '\t':
				out[out.length] = ' ';
				break;
			default:
				if (count > 0) {
					if (!strip) {
						out[out.length] = '_';
					}
				}
				else {
					out[out.length] = c;
				}
		}
	}
	return out.join("");
};

/*
	Strip game comments from a PGN string. If second
	parameter set false true then comments will be replaced
	by an underscore.
*/
Pgn.prototype.stripIt = function (val, strip) {
	var count = 0;
	var out = new Array();
	var inComment = false;
	for (var i=0;i<val.length;i++) {
		var c = val.charAt(i);
		switch (c) {
			case '(':
				if (!strip) {
					out[out.length] = '_';
				}
				if(!inComment) {
					count++;
				}
				break;
			case '{':
				inComment = true;
				if (!strip) {
					out[out.length] = '_';
				}
				count++;
				break;
			case '}':
				count--;
				if (!strip) {
					out[out.length] = '_';
				}
				inComment = false;
				break;
			case ')':
				if(!inComment) {
					count--;
				}
				if (!strip) {
					out[out.length] = '_';
				}
				break;
			case '\t':
				out[out.length] = ' ';
				break;
			default:
				if (count > 0) {
					if (!strip) {
						out[out.length] = '_';
					}
				}
				else {
					out[out.length] = c;
				}
		}
	}
	return out.join("");
};
<|endoftext|>


<commit_before>"use strict";

module.exports = function (config, helpers) {
  var grunt = this;

  grunt.registerTask("compilation_step", "Runs iterative all compilation steps from config", function () {
    var moduleData = grunt.config.get("modules.active");
    if (moduleData == null) {
      return grunt.fail.fatal("set_active_module must be run first");
    }
    var steps = grunt.config.get("compilation.stack");
    var step = steps.shift();
    grunt.config.set("compilation.stack", steps);
    var compiler = helpers.loadCompiler(step.compiler);
    grunt.file.setBase(moduleData.paths.tmp);
    var result = compiler.process.call(grunt, moduleData, step, helpers);
    if (result instanceof Array || typeof result === "string") {
      grunt.task.run(result);
    }
    grunt.task.run("compilation_step_done");
    if (steps.length) {
      grunt.task.run("compilation_step");
    }
  });

  grunt.registerTask("compilation", "Runs compilation of module as defined within config", function () {
    var moduleData = grunt.config.get("modules.active");
    if (moduleData == null) {
      return grunt.fail.fatal("set_active_module must be run first");
    }
    var dev = grunt.config.get("development");
    var compilationId = "sets." + config.types[moduleData.meta.type.id].compilation;

    grunt.task.run("increment_module_build");
    grunt.config.set("compilation.stack", helpers.getCompilation(compilationId, dev));
    if (grunt.config.get("compilation.stack").length) {
      grunt.task.run("compilation_step");
    }
  });

  grunt.registerTask("compilation_step_done", "Resets the cwd", function () { grunt.file.setBase(config.cwd); });

  return {};
};
<commit_msg>Add compilation logging<commit_after>"use strict";

module.exports = function (config, helpers) {
  var grunt = this;

  grunt.registerTask("compilation_step", "Runs iterative all compilation steps from config", function () {
    var moduleData = grunt.config.get("modules.active");
    if (moduleData == null) {
      return grunt.fail.fatal("set_active_module must be run first");
    }
    var steps = grunt.config.get("compilation.stack");
    var step = steps.shift();
    grunt.config.set("compilation.stack", steps);
    var compiler = helpers.loadCompiler(step.compiler);
    grunt.log.ok("Process '" + step.compiler + "' compilation");
    grunt.file.setBase(moduleData.paths.tmp);
    var result = compiler.process.call(grunt, moduleData, step, helpers);
    if (result instanceof Array || typeof result === "string") {
      grunt.task.run(result);
    }
    grunt.task.run("compilation_step_done");
    if (steps.length) {
      grunt.task.run("compilation_step");
    }
  });

  grunt.registerTask("compilation", "Runs compilation of module as defined within config", function () {
    var moduleData = grunt.config.get("modules.active");
    if (moduleData == null) {
      return grunt.fail.fatal("set_active_module must be run first");
    }
    var dev = grunt.config.get("development");
    var compilationId = "sets." + config.types[moduleData.meta.type.id].compilation;

    grunt.task.run("increment_module_build");
    grunt.config.set("compilation.stack", helpers.getCompilation(compilationId, dev));
    if (grunt.config.get("compilation.stack").length) {
      grunt.task.run("compilation_step");
    }
  });

  grunt.registerTask("compilation_step_done", "Resets the cwd", function () { grunt.file.setBase(config.cwd); });

  return {};
};
<|endoftext|>