[GladiatorTool] backup

[GladiatorTool] backup

//
// Comment the selected block of text using single line comments and indent it
//
macro CommentBlock( )
{
  hbuf = GetCurrentBuf( );
  hwnd = GetCurrentWnd( );

  sel = GetWndSel( hwnd );

  iLine = sel.lnFirst;

  while ( iLine <= sel.lnLast )
  {
    szLine = GetBufLine( hbuf, iLine );
    szLine = cat( "//	", szLine );
    PutBufLine( hbuf, iLine, szLine );
    iLine = iLine + 1;
  }

  if ( sel.lnFirst == sel.lnLast )
  {
    tabSize      = _tsGetTabSize( ) - 1;
    sel.ichFirst = sel.ichFirst + tabSize;
    sel.ichLim   = sel.ichLim + tabSize;
  }
  SetWndSel( hwnd, sel );
}

//
// Comment the selected block of text using single line comments and indent it
//
macro CommentBlock3( )
{
  hbuf = GetCurrentBuf( );
  hwnd = GetCurrentWnd( );

  sel = GetWndSel( hwnd );

  iLine = sel.lnFirst;

  while ( iLine <= sel.lnLast )
  {
    szLine = GetBufLine( hbuf, iLine );
    szLine = cat( "///  ", szLine );
    PutBufLine( hbuf, iLine, szLine );
    iLine = iLine + 1;
  }

  if ( sel.lnFirst == sel.lnLast )
  {
    tabSize      = _tsGetTabSize( ) - 1;
    sel.ichFirst = sel.ichFirst + tabSize;
    sel.ichLim   = sel.ichLim + tabSize;
  }
  SetWndSel( hwnd, sel );
}

//
// Undo the CommentBlock for the selected text.
//
macro UnCommentBlock( )
{
  hbuf = GetCurrentBuf( );
  hwnd = GetCurrentWnd( );

  sel = GetWndSel( hwnd );

  iLine = sel.lnFirst;

  tabSize = 0;
  while ( iLine <= sel.lnLast )
  {
    szLine    = GetBufLine( hbuf, iLine );
    len       = strlen( szLine );
    szNewLine = "";
    if ( len > 1 )
    {
      if ( ( szLine[0] == "/" ) && ( szLine[1] == "/" ) )
      {
        if ( len > 2 )
        {
          if ( AsciiFromChar( szLine[2] ) == 9 )
          {
            tabSize   = _tsGetTabSize( ) - 1;
            szNewLine = strmid( szLine, 3, strlen( szLine ) );
          }
        }

        if ( szNewLine == "" )
        {
          szNewLine = strmid( szLine, 2, strlen( szLine ) );
          tabSize   = 2;
        }

        PutBufLine( hbuf, iLine, szNewLine );
      }
    }
    iLine = iLine + 1;
  }

  if ( sel.lnFirst == sel.lnLast )
  {
    sel.ichFirst = sel.ichFirst - tabSize;
    sel.ichLim   = sel.ichLim - tabSize;
  }

  SetWndSel( hwnd, sel );
}

//
// Undo the CommentBlock for the selected text.
//
macro UnCommentBlock3( )
{
  hbuf = GetCurrentBuf( );
  hwnd = GetCurrentWnd( );

  sel = GetWndSel( hwnd );

  iLine = sel.lnFirst;

  tabSize = 0;
  while ( iLine <= sel.lnLast )
  {
    szLine    = GetBufLine( hbuf, iLine );
    len       = strlen( szLine );
    szNewLine = "";
    if ( len > 2 )
    {
      if ( ( szLine[0] == "/" ) && ( szLine[1] == "/" ) && ( szLine[2] == "/" ) )
      {
        if ( len > 3 )
        {
          if ( AsciiFromChar( szLine[3] ) == 9 )
          {
            szNewLine = strmid( szLine, 3, strlen( szLine ) );
          }
        }

        if ( szNewLine == "" )
        {
          szNewLine = strmid( szLine, 5, strlen( szLine ) );
        }

        PutBufLine( hbuf, iLine, szNewLine );
      }
    }
    iLine = iLine + 1;
  }

  if ( sel.lnFirst == sel.lnLast )
  {
    sel.ichFirst = sel.ichFirst - tabSize;
    sel.ichLim   = sel.ichLim - tabSize;
  }

  SetWndSel( hwnd, sel );
}

macro _tsGetTabSize( )
{
  szTabSize = GetReg( "TabSize" );

  if ( szTabSize != "" )
  {
    tabSize = AsciiFromChar( szTabSize[0] ) - AsciiFromChar( "0" );
  }
  else
  {
    tabSize = 4;
  }

  return( tabSize );
}

//
// Reformat a selected comment block to wrap text at 80 columns.
// The start of the selection (upper left most character of the selection) is
// handled specially, in that it specifies the left most column at which all
// lines will begin.  For example, if the following block was selected starting
// at the @ symbol, through the last line of the block...
//------------------------------------------------------------------------------
// preamble:	@ This is a line that will be wrapped keeping the "at" symbol in its current column.
// All lines following it that are selected will use that as their starting column.  See below to see how the wrapping
// works for this block of text.
//------------------------------------------------------------------------------
// preamble:	@ This is a line that will be wrapped keeping the "at" symbol in
//				its current column. All lines following it that are selected
//				will use that as their starting column.  See below to see how
//				the wrapping works for this block of text.
//
macro tsReformatCommentBlock( )
{
  hbuf = GetCurrentBuf( );
  hwnd = GetCurrentWnd( );

  sel = GetWndSel( hwnd );

  tabSize     = _tsGetTabSize( );
  leftTextCol = 0 - 1;
  colWrap     = 80;

  // Find the starting column, and create a Margin string
  ichFirst = sel.ichFirst;

  // Single line comment reformat?
  if ( ( sel.ichFirst == sel.ichLim ) && ( sel.lnFirst == sel.lnLast ) )
  {
    ichFirst = 0;
  }

  rec = _tsGetStartColumn( hbuf, ichFirst, sel.lnFirst );

  if ( rec == "" )
  {
    stop;
  }

  colLeftMargin = rec.colMargin;
  szMargin      = "";

  colComment = 0;
  if ( rec.colComment >= 0 )
  {
    colComment = rec.colComment + 2;
    szMargin   = _tsAddWhiteToColumn( szMargin, 0, rec.colComment, tabSize );
    szMargin   = cat( szMargin, "//" );
  }

  szMargin = _tsAddWhiteToColumn( szMargin, colComment, rec.colMargin, tabSize );

  rec = "";

  szCurMargin = "";
  if ( ichFirst != 0 )
  {
    szLine      = GetBufLine( hbuf, sel.lnFirst );
    szCurMargin = strmid( szLine, 0, ichFirst );
  }
  else
  {
    szCurMargin = szMargin;
    szMargin    = "";
  }

  insertLine  = sel.lnFirst;
  iLine       = sel.lnFirst;
  szRemainder = "";
  while ( 1 )
  {
    //		msg("$0-" # iLine # ":" # szRemainder);
    rec      = _tsGetNextCommentString( hbuf, ichFirst, szRemainder, iLine, sel.lnLast, colWrap );
    ichFirst = 0;

    if ( rec == "" )
    {
      break;
    }

    //		msg("$1-" # rec.ln # ":" # rec.szComment);
    szLine = rec.szComment;

    ich = 0;
    col = colLeftMargin;
    len = strlen( szLine );

    ichPrevCharToWhite = 0 - 1;
    ichPrevWhiteToChar = 0 - 1;
    //		msg("Leftovers @szRemainder@");

    while ( ich < len )
    {
      if ( AsciiFromChar( szLine[ich] ) == 9 )
      {
        col = ( ( ( col + tabSize ) / tabSize ) * tabSize );
      }
      else
      {
        col = col + 1;
      }

      if ( col > colWrap )
      {
        break;
      }

      fIsWhitespace  = _tsIsWhitespaceChar( szLine[ich] );
      fIsWhitespace1 = 1;

      if ( ich + 1 < len )
      {
        fIsWhitespace1 = _tsIsWhitespaceChar( szLine[ich + 1] );
      }

      if ( !fIsWhitespace && fIsWhitespace1 )
      {
        ichPrevCharToWhite = ich;
      }

      ich = ich + 1;
    }

    if ( ichPrevCharToWhite > 0 )
    {
      //			msg("$2:" # strmid(szLine, 0, ichPrevCharToWhite + 1));
      ich = ichPrevCharToWhite + 1;

      while ( ich < len )
      {
        if ( !_tsIsWhitespaceChar( szLine[ich] ) )
        {
          ichPrevWhiteToChar = ich - 1;
          //					msg("$3:" # strmid(szLine, ichPrevWhiteToChar + 1, len));
          break;
        }
        ich = ich + 1;
      }
    }

    if ( ( ichPrevCharToWhite > 0 ) && ( col > colWrap ) )
    {
      szNewLine   = cat( szCurMargin, strmid( szLine, 0, ichPrevCharToWhite + 1 ) );
      szRemainder = "";
      if ( ichPrevWhiteToChar > 0 )
      {
        szRemainder = strmid( szLine, ichPrevWhiteToChar + 1, len );
      }

      if ( ichPrevCharToWhite > ichPrevWhiteToChar )
      {
        msg( "!!!Wrap, duplicating word " # ichPrevWhiteToChar # " " # ichPrevCharToWhite # " " # szNewLine # " >>> " # szRemainder );
      }
      //				msg(szLine);
      //				msg(col # " " # ichPrevWhiteToChar # " " # ichPrevCharToWhite # " " # szNewLine # " >>> " # szRemainder);
    }
    else if ( szLine != "" )
    {
      szNewLine   = cat( szCurMargin, szLine );
      szRemainder = "";
      //			sel.lnLast = sel.lnLast + 1;
    }

    iLine = rec.ln;
    if ( insertLine == iLine )
    {
      iLine      = iLine + 1;
      sel.lnLast = sel.lnLast + 1;

      //			msg("$5-" # insertLine # ":" # szNewLine);
      InsBufLine( hbuf, insertLine, szNewLine );
    }
    else
    {
      szLine = GetBufLine( hbuf, insertLine );
      if ( szLine != szNewLine )
      {
        //				msg("$6-" # insertLine # ":" # szNewLine);
        PutBufLine( hbuf, insertLine, szNewLine );
      }
    }
    insertLine = insertLine + 1;

    if ( szMargin != "" )
    {
      szCurMargin = szMargin;
      szMargin    = "";
    }
  }

  while ( insertLine <= sel.lnLast )
  {
    DelBufLine( hbuf, insertLine );
    sel.lnLast = sel.lnLast - 1;
  }

  len = GetBufLineLength( hbuf, insertLine - 1 );

  sel.ichFirst = len;
  sel.ichLim   = len;
  sel.lnFirst  = sel.lnLast;
  SetWndSel( hwnd, sel );
}

macro _tsAddWhiteToColumn( sz, col0, col, tabSize )
{
  szTabs   = "																														";
  szSpaces = "                ";

  tabs0 = col0 / tabSize;
  tabs  = ( col / tabSize ) - tabs0;

  if ( tabs == 0 )
  {
    foo = col0;
  }
  else
  {
    foo = ( tabs + tabs0 ) * tabSize;
  }
  spaces = col - foo;
  //	msg(col0 # " " # col # " " # tabs # " " # spaces # " " # tabs0);

  if ( tabs )
  {
    sz = cat( sz, strmid( szTabs, 0, tabs ) );
  }

  if ( spaces )
  {
    sz = cat( sz, strmid( szSpaces, 0, spaces ) );
  }

  return( sz );
}

macro _tsGetStartColumn( hbuf, ichBegin, ln )
{
  szLine  = GetBufLine( hbuf, ln );
  len     = strlen( szLine );
  tabSize = _tsGetTabSize( );
  ich     = 0;

  colMargin  = 0;
  colComment = 0 - 1;

  rec            = "";
  rec.colMargin  = colMargin;
  rec.colComment = colComment;

  while ( ich < len )
  {
    if ( AsciiFromChar( szLine[ich] ) == 9 )
    {
      colMargin = ( ( ( colMargin + tabSize ) / tabSize ) * tabSize );
    }
    else
    {
      colMargin = colMargin + 1;
    }

    if ( colComment < 0 )
    {
      if ( ich + 1 < len )
      {
        if ( ( szLine[ich] == "/" ) && ( szLine[ich + 1] == "/" ) )
        {
          colComment = colMargin - 1;
          ich        = ich + 2;
          colMargin  = colMargin + 1;
          continue;
        }
      }
    }

    if ( ich >= ichBegin )
    {
      if ( !_tsIsWhitespaceChar( szLine[ich] ) )
      {
        rec.colMargin  = colMargin - 1;
        rec.colComment = colComment;
        //				msg(szLine[ich]);
        return( rec );
      }
    }

    ich = ich + 1;
  }

  return( rec );
}

macro _tsGetNextCommentString( hbuf, ichSkip, szRemainder, ln, lnLast, colWrap )
{
  rec = "";

  // Go until we get a string that is at least long enough to fill a line
  // or, we run out of lines.
  if ( ( szRemainder == "" ) && ( ln > lnLast ) )
  {
    return( "" );
  }

  ichFirst = ichSkip;
  //	msg(ichSkip);
  while ( 1 )
  {
    if ( ln > lnLast )
    {
      rec.szComment = szRemainder;
      rec.ln        = ln;
      return( rec );
    }

    cchRemainder = strlen( szRemainder );

    if ( cchRemainder > colWrap )
    {
      rec.szComment = szRemainder;
      rec.ln        = ln;
      return( rec );
    }

    szLine = GetBufLine( hbuf, ln );
    len    = strlen( szLine );

    if ( ichSkip == 0 )
    {
      ichFirst = _tsSkipPastCommentAndWhitespace( szLine, len );
    }
    ichSkip = 0;

    ichLast = len - 1;

    // Now, strip out all whitespace at the end of the line
    while ( ichLast >= ichFirst )
    {
      if ( !_tsIsWhitespaceChar( szLine[ichLast] ) )
      {
        break;
      }
      ichLast = ichLast - 1;
    }

    // Entire line is whitespace?
    if ( ichLast < ichFirst )
    {
      if ( szRemainder == "" )
      {
        ln = ln + 1;
      }
      rec.szComment = szRemainder;
      rec.ln        = ln;
      return( rec );
    }
    // length of the non whitespaced comment + 1 space + cchRemainder
    if ( ( ichLast + 1 ) - ichFirst + cchRemainder + 1 > 255 )
    {
      // It may not format the current line quite right, but
      // but at least we won't throw away some of the comment.
      rec.szComment = szRemainder;
      rec.ln        = ln;
      return( rec );
    }

    if ( szRemainder != "" )
    {
      szRemainder = cat( szRemainder, " " );
    }
    szRemainder = cat( szRemainder, strmid( szLine, ichFirst, ichLast + 1 ) );
    ln          = ln + 1;
  }
}

macro _tsSkipPastCommentAndWhitespace( szLine, len )
{
  ichFirst = 0;
  // Skip past the comment initiator "//" if there is one.
  while ( ichFirst < len )
  {
    if ( ichFirst + 1 < len )
    {
      if ( ( szLine[ichFirst] == "/" ) && ( szLine[ichFirst + 1] == "/" ) )
      {
        ichFirst = ichFirst + 2;
        break;
      }
    }
    ichFirst = ichFirst + 1;
  }

  // If no comment found in line, then start from the beginning
  if ( ichFirst >= len )
  {
    ichFirst = 0;
  }

  ichFirst = ichFirst;
  // Now, strip out all whitespace after the comment start.
  while ( ichFirst < len )
  {
    if ( !_tsIsWhitespaceChar( szLine[ichFirst] ) )
    {
      break;
    }
    ichFirst = ichFirst + 1;
  }

  return( ichFirst );
}

//
// Comment the selected block of text using single line comments and indent it
//
macro CommentBlock()
{
	hbuf = GetCurrentBuf();
	hwnd = GetCurrentWnd();

	sel = GetWndSel(hwnd);

	iLine = sel.lnFirst;

	while (iLine <= sel.lnLast)
	{
		szLine = GetBufLine(hbuf, iLine);
		szLine = cat("//	", szLine);
		PutBufLine(hbuf, iLine, szLine);
		iLine = iLine + 1;
	}

	if (sel.lnFirst == sel.lnLast)
	{
		tabSize = _tsGetTabSize() - 1;
		sel.ichFirst = sel.ichFirst + tabSize;
		sel.ichLim = sel.ichLim + tabSize;
	}
	SetWndSel(hwnd, sel);
}

//
// Comment the selected block of text using single line comments and indent it
//
macro CommentBlock3()
{
	hbuf = GetCurrentBuf();
	hwnd = GetCurrentWnd();

	sel = GetWndSel(hwnd);

	iLine = sel.lnFirst;

	while (iLine <= sel.lnLast)
	{
		szLine = GetBufLine(hbuf, iLine);
		szLine = cat("///  ", szLine);
		PutBufLine(hbuf, iLine, szLine);
		iLine = iLine + 1;
	}

	if (sel.lnFirst == sel.lnLast)
	{
		tabSize = _tsGetTabSize() - 1;
		sel.ichFirst = sel.ichFirst + tabSize;
		sel.ichLim = sel.ichLim + tabSize;
	}
	SetWndSel(hwnd, sel);
}

//
// Undo the CommentBlock for the selected text.
//
macro UnCommentBlock()
{
	hbuf = GetCurrentBuf();
	hwnd = GetCurrentWnd();

	sel = GetWndSel(hwnd);

	iLine = sel.lnFirst;

	tabSize = 0;
	while (iLine <= sel.lnLast)
	{
		szLine = GetBufLine(hbuf, iLine);
		len = strlen(szLine);
		szNewLine = "";
		if (len > 1)
		{
			if (szLine[0] == "/" && szLine[1] == "/")
			{
				if (len > 2)
				{
					if (AsciiFromChar(szLine[2]) == 9)
					{
						tabSize = _tsGetTabSize() - 1;
						szNewLine = strmid(szLine, 3, strlen(szLine));
					}
				}

				if (szNewLine == "")
				{
					szNewLine = strmid(szLine, 2, strlen(szLine));
					tabSize = 2;
				}

				PutBufLine(hbuf, iLine, szNewLine);
			}
		}
		iLine = iLine + 1;
	}

	if (sel.lnFirst == sel.lnLast)
	{
		sel.ichFirst = sel.ichFirst - tabSize;
		sel.ichLim = sel.ichLim - tabSize;
	}

	SetWndSel(hwnd, sel);
}

//
// Undo the CommentBlock for the selected text.
//
macro UnCommentBlock3()
{
	hbuf = GetCurrentBuf();
	hwnd = GetCurrentWnd();

	sel = GetWndSel(hwnd);

	iLine = sel.lnFirst;

	tabSize = 0;
	while (iLine <= sel.lnLast)
	{
		szLine = GetBufLine(hbuf, iLine);
		len = strlen(szLine);
		szNewLine = "";
		if (len > 2)
		{
			if (szLine[0] == "/" && szLine[1] == "/" && szLine[2] == "/")
			{
				if (len > 3)
				{
					if (AsciiFromChar(szLine[3]) == 9)
					{
						szNewLine = strmid(szLine, 3, strlen(szLine));
					}
				}

				if (szNewLine == "")
				{
					szNewLine = strmid(szLine, 5, strlen(szLine));
				}

				PutBufLine(hbuf, iLine, szNewLine);
			}
		}
		iLine = iLine + 1;
	}

	if (sel.lnFirst == sel.lnLast)
	{
		sel.ichFirst = sel.ichFirst - tabSize;
		sel.ichLim = sel.ichLim - tabSize;
	}

	SetWndSel(hwnd, sel);
}

macro _tsGetTabSize()
{
	szTabSize = GetReg("TabSize");

	if (szTabSize != "")
	{
		tabSize = AsciiFromChar(szTabSize[0]) - AsciiFromChar("0");
	}
	else
	{
		tabSize = 4;
	}

	return tabSize;
}

//
// Reformat a selected comment block to wrap text at 80 columns.
// The start of the selection (upper left most character of the selection) is
// handled specially, in that it specifies the left most column at which all
// lines will begin.  For example, if the following block was selected starting
// at the @ symbol, through the last line of the block...
//------------------------------------------------------------------------------
// preamble:	@ This is a line that will be wrapped keeping the "at" symbol in its current column.
// All lines following it that are selected will use that as their starting column.  See below to see how the wrapping
// works for this block of text.
//------------------------------------------------------------------------------
// preamble:	@ This is a line that will be wrapped keeping the "at" symbol in
//				its current column. All lines following it that are selected
//				will use that as their starting column.  See below to see how
//				the wrapping works for this block of text.
//
macro tsReformatCommentBlock()
{
	hbuf = GetCurrentBuf();
	hwnd = GetCurrentWnd();

	sel = GetWndSel(hwnd);

	tabSize = _tsGetTabSize();
	leftTextCol = 0 - 1;
	colWrap = 80;

	// Find the starting column, and create a Margin string
	ichFirst = sel.ichFirst;

	// Single line comment reformat?
	if (sel.ichFirst == sel.ichLim && sel.lnFirst == sel.lnLast)
	{
		ichFirst = 0;
	}

	rec = _tsGetStartColumn(hbuf, ichFirst, sel.lnFirst);

	if (rec == "")
		stop;

	colLeftMargin = rec.colMargin;
	szMargin = "";

	colComment = 0;
	if (rec.colComment >= 0)
	{
		colComment = rec.colComment + 2
		szMargin = _tsAddWhiteToColumn(szMargin, 0, rec.colComment, tabSize);
		szMargin = cat(szMargin, "//");
	}

	szMargin = _tsAddWhiteToColumn(szMargin, colComment, rec.colMargin, tabSize);

	rec = "";

	szCurMargin = "";
	if (ichFirst != 0)
	{
		szLine = GetBufLine(hbuf, sel.lnFirst);
		szCurMargin = strmid(szLine, 0, ichFirst);
	}
	else
	{
		szCurMargin = szMargin;
		szMargin = "";
	}

	insertLine = sel.lnFirst;
	iLine = sel.lnFirst;
	szRemainder = "";
	while (1)
	{
//		msg("$0-" # iLine # ":" # szRemainder);
		rec = _tsGetNextCommentString(hbuf, ichFirst, szRemainder, iLine, sel.lnLast, colWrap);
		ichFirst = 0;

		if (rec == "")
			break;

//		msg("$1-" # rec.ln # ":" # rec.szComment);
		szLine = rec.szComment;

		ich = 0;
		col = colLeftMargin;
		len = strlen(szLine);

		ichPrevCharToWhite = 0-1;
		ichPrevWhiteToChar = 0-1;
//		msg("Leftovers @szRemainder@");

		while (ich < len)
		{
			if (AsciiFromChar(szLine[ich]) == 9)
			{
				col = (((col + tabSize) / tabSize) * tabSize);
			}
			else
			{
				col = col + 1;
			}

			if (col > colWrap)
				break;

			fIsWhitespace = _tsIsWhitespaceChar(szLine[ich]);
			fIsWhitespace1 = 1;

			if (ich + 1 < len)
			{
				fIsWhitespace1 = _tsIsWhitespaceChar(szLine[ich + 1]);
			}

			if (!fIsWhitespace && fIsWhitespace1)
				ichPrevCharToWhite = ich;

			ich = ich + 1;
		}

		if (ichPrevCharToWhite > 0)
		{
//			msg("$2:" # strmid(szLine, 0, ichPrevCharToWhite + 1));
			ich = ichPrevCharToWhite + 1;

			while (ich < len)
			{
				if (!_tsIsWhitespaceChar(szLine[ich]))
				{
					ichPrevWhiteToChar = ich - 1;
//					msg("$3:" # strmid(szLine, ichPrevWhiteToChar + 1, len));
					break;
				}
				ich = ich + 1;
			}
		}

		if (ichPrevCharToWhite > 0 && col > colWrap)
		{
			szNewLine = cat(szCurMargin, strmid(szLine, 0, ichPrevCharToWhite + 1));
			szRemainder = "";
			if (ichPrevWhiteToChar > 0)
				szRemainder = strmid(szLine, ichPrevWhiteToChar + 1, len);

			if (ichPrevCharToWhite > ichPrevWhiteToChar)
				msg("!!!Wrap, duplicating word " # ichPrevWhiteToChar # " " # ichPrevCharToWhite # " " # szNewLine # " >>> " # szRemainder);
//				msg(szLine);
//				msg(col # " " # ichPrevWhiteToChar # " " # ichPrevCharToWhite # " " # szNewLine # " >>> " # szRemainder);
		}
		else if (szLine != "")
		{
			szNewLine = cat(szCurMargin, szLine );
			szRemainder = "";
//			sel.lnLast = sel.lnLast + 1;
		}

		iLine = rec.ln;
		if (insertLine == iLine)
		{
			iLine = iLine + 1;
			sel.lnLast = sel.lnLast + 1;

//			msg("$5-" # insertLine # ":" # szNewLine);
			InsBufLine(hbuf, insertLine, szNewLine);
		}
		else
		{
			szLine = GetBufLine(hbuf, insertLine);
			if (szLine != szNewLine)
			{
//				msg("$6-" # insertLine # ":" # szNewLine);
				PutBufLine(hbuf, insertLine, szNewLine);
			}
		}
		insertLine = insertLine + 1;

		if (szMargin != "")
		{
			szCurMargin = szMargin;
			szMargin = "";
		}
	}

	while (insertLine <= sel.lnLast)
	{
		DelBufLine(hbuf, insertLine);
		sel.lnLast = sel.lnLast - 1;
	}

	len = GetBufLineLength(hbuf, insertLine-1);

	sel.ichFirst = len;
	sel.ichLim = len;
	sel.lnFirst = sel.lnLast;
	SetWndSel(hwnd, sel);
}

macro _tsAddWhiteToColumn(sz, col0, col, tabSize)
{
	szTabs = "																														";
	szSpaces = "                ";

	tabs0 = col0 / tabSize;
	tabs = (col / tabSize) - tabs0;

	if (tabs == 0)
		foo = col0;
	else
		foo = (tabs + tabs0) * tabSize;
	spaces = col - foo;
//	msg(col0 # " " # col # " " # tabs # " " # spaces # " " # tabs0);

	if (tabs)
		sz = cat(sz, strmid(szTabs, 0, tabs));

	if (spaces)
		sz = cat(sz, strmid(szSpaces, 0, spaces));

	return sz;
}

macro _tsGetStartColumn(hbuf, ichBegin, ln)
{
	szLine = GetBufLine(hbuf, ln);
	len = strlen(szLine);
	tabSize = _tsGetTabSize();
	ich = 0;

	colMargin = 0;
	colComment = 0-1;

	rec = "";
	rec.colMargin = colMargin;
	rec.colComment = colComment;

	while (ich < len)
	{
		if (AsciiFromChar(szLine[ich]) == 9)
		{
			colMargin = (((colMargin + tabSize) / tabSize) * tabSize);
		}
		else
		{
			colMargin = colMargin + 1;
		}

		if (colComment < 0)
		{
			if (ich + 1 < len)
			{
				if (szLine[ich] == "/" && szLine[ich+1] == "/")
				{
					colComment = colMargin - 1;
					ich = ich + 2;
					colMargin = colMargin + 1;
					continue;
				}
			}
		}

		if (ich >= ichBegin)
		{
			if (!_tsIsWhitespaceChar(szLine[ich]))
			{
				rec.colMargin = colMargin - 1;
				rec.colComment = colComment;
//				msg(szLine[ich]);
				return rec;
			}
		}

		ich = ich + 1;
	}

	return rec;
}

macro _tsGetNextCommentString(hbuf, ichSkip, szRemainder, ln, lnLast, colWrap)
{
	rec = "";

	// Go until we get a string that is at least long enough to fill a line
	// or, we run out of lines.
	if (szRemainder == "" && ln > lnLast)
		return "";

	ichFirst = ichSkip;
//	msg(ichSkip);
	while (1)
	{
		if (ln > lnLast)
		{
			rec.szComment = szRemainder;
			rec.ln = ln;
			return rec;
		}

		cchRemainder = strlen(szRemainder);

		if (cchRemainder > colWrap)
		{
			rec.szComment = szRemainder;
			rec.ln = ln;
			return rec;
		}

		szLine = GetBufLine(hbuf, ln);
		len = strlen(szLine);

		if (ichSkip == 0)
			ichFirst = _tsSkipPastCommentAndWhitespace(szLine, len);
		ichSkip = 0;

		ichLast = len - 1;

		// Now, strip out all whitespace at the end of the line
		while (ichLast >= ichFirst)
		{
			if (!_tsIsWhitespaceChar(szLine[ichLast]))
			{
				break;
			}
			ichLast = ichLast - 1;
		}

		// Entire line is whitespace?
		if (ichLast < ichFirst)
		{
			if (szRemainder == "")
				ln = ln + 1;
			rec.szComment = szRemainder;
			rec.ln = ln;
			return rec;

		}
		// length of the non whitespaced comment + 1 space + cchRemainder
		if ((ichLast + 1) - ichFirst + cchRemainder + 1 > 255)
		{
			// It may not format the current line quite right, but
			// but at least we won't throw away some of the comment.
			rec.szComment = szRemainder;
			rec.ln = ln;
			return rec;
		}

		if (szRemainder != "")
			szRemainder = cat(szRemainder, " ");
		szRemainder = cat(szRemainder, strmid(szLine, ichFirst, ichLast + 1));
		ln = ln + 1;
	}
}

macro _tsSkipPastCommentAndWhitespace(szLine, len)
{
	ichFirst = 0;
	// Skip past the comment initiator "//" if there is one.
	while (ichFirst < len)
	{
		if (ichFirst + 1 < len)
		{
			if (szLine[ichFirst] == "/" && szLine[ichFirst+1] == "/")
			{
				ichFirst = ichFirst + 2;
				break;
			}
		}
		ichFirst = ichFirst + 1;
	}

	// If no comment found in line, then start from the beginning
	if (ichFirst >= len)
		ichFirst = 0;

	ichFirst = ichFirst;
	// Now, strip out all whitespace after the comment start.
	while (ichFirst < len)
	{
		if (!_tsIsWhitespaceChar(szLine[ichFirst]))
		{
			break;
		}
		ichFirst = ichFirst + 1;
	}

	return ichFirst;
}


perms

perms

#!/usr/bin/make -f

# Uncomment this to turn on verbose mode.
export DH_VERBOSE=1
export DH_OPTIONS=-v

%:
       dh  $@@

override_dh_auto_configure:
       dh_auto_configure -Scmake -- \
               -DCMAKE_INSTALL_PREFIX="@(CMAKE_INSTALL_PREFIX)" \
               -DCMAKE_PREFIX_PATH="@(CMAKE_INSTALL_PREFIX)" \
               -DCATKIN_PACKAGE_PREFIX="@(CATKIN_PACKAGE_PREFIX)" \
               -DCATKIN=YES
       dh_auto_configure -Spython_distutils

override_dh_auto_install:
       dh_auto_install -Scmake
       dh_auto_install -Spython_distutils -- --prefix="@(CMAKE_INSTALL_PREFIX)"

override_dh_auto_build:
       dh_auto_build -Scmake
       dh_auto_build -Spython_distutils


as per dmitri request

as per dmitri request

class Herd.AssetsIndexController extends Ember.ArrayController
  sortProperties: ['position']

  +computed arrangedContent.@each.position #, arrangedContent.@each.parentAsset,
  filteredContent: ->
    @arrangedContent.filterBy('parentAsset', null)

  updateSortOrder: (indexes) ->
    @forEach (asset) ->
      asset.position = indexes[asset.id]
    @model.invoke 'save'

  actions:
    destroy: (asset) ->
      asset.destroyRecord()
      @model.removeObject asset

    uploadFinished: (resp) ->
      @store.pushPayload resp
      @model.pushObject @store.getById('asset', resp.asset?.id)

    uploadProgressed: (e) ->
      console.log('prog ', e)

class Herd.AssetsIndexController extends Ember.ArrayController
  sortProperties: ['position']

  +computed arrangedContent.@each.position #, arrangedContent.@each.parentAsset,
  filteredContent: ->
    @arrangedContent.filterBy('parentAsset', null)

  updateSortOrder: (indexes) ->
    @forEach (asset) ->
      asset.position = indexes[asset.id]
    @model.invoke 'save'

  actions:
    destroy: (asset) ->
      asset.destroyRecord()
      @model.removeObject(asset)

    uploadFinished: (resp) ->
      @store.pushPayload resp
      @model.pushObject @store.getById('asset', resp.asset?.id)

    uploadProgressed: (e) ->
      console.log('prog ', e)


3.20:  Fix styling for linked widgets (eg. combobox entries)

${
import os
import math

gtk_major, gtk_minor, gtk_patch = map(int, gtk.split('.'))
treeview_pseudo_element = gtk_major >= 3 and gtk_minor >= 16

def my_floor(num):
    return int(math.floor(num))

def my_ceil(num):
    return int(math.ceil(num))

# Should we set the line width in the engine to 2.25, and draw non pixel aligned lines?
# Are these already the correct sizes for the XO?

# These sizes need to be sanity checked ...
if scaling == "100":
    xo = True
    line_width = 2.0        # 2.25px, rounded down
    thick_line_width = 3.5  # 3.5
    subcell_size = 15
    icon_base = 11
    bullet_size = 9.5
    font_height = 24
    default_padding = 6
    toolbutton_padding = 10
    radio_size = 26
    scale_trough_margin = 8
else: # About 72% of the XO size, adjusted so that eg. toolbuttons work
    xo = False
    line_width = 2.0            # 1.62 rounded up
    thick_line_width = 3.0      # 2.52
    subcell_size = 11           # 10.8
    icon_base = 8               # 7.92
    bullet_size = 6.5           # 6.84
    # This is a guess on the font size (Sans 10 at 96 DPI)
    font_height = 17
    default_padding = 4         # 4.32
    toolbutton_padding = 7      # 7.68
    radio_size = 18             # 18.72
    scale_trough_margin = 6     # 5.76

scale_slider_width = my_floor(2 * subcell_size + line_width)
thickness = my_ceil(line_width)

icon_small = icon_base * 3
icon_large = icon_base * 5

disabled_opacity = 0.5

}

* {
    -sugar-focus-line: @white;

    /* 0.05 works good for both the sugar and sugar-xo themes */
    -GtkWidget-cursor-aspect-ratio: 0.05;

    -GtkWidget-wide-separators: true;
    -GtkWidget-separator-height: $thickness;
    -GtkWidget-separator-width: $thickness;

    -GtkWidget-scroll-arrow-hlength: $subcell_size;
    -GtkWidget-scroll-arrow-vlength: $subcell_size;

    -GtkRange-activate-slider: 1;

    -GtkScrolledWindow-scrollbar-spacing: 0;

    -GtkExpander-expander-size: $font_height;
    -GtkExpander-expander-spacing: 2;

    -GtkTreeView-expander-size: $font_height;

    -GtkArrow-arrow-size: 1.0;

    -GtkToolbar-space-size: $(2*subcell_size);

    -GtkProgressBar-min-horizontal-bar-height: $subcell_size;
    -GtkProgressBar-min-vertical-bar-width: $subcell_size;

    -GtkCheckButton-indicator-size: $radio_size;
    -GtkCheckButton-indicator-spacing: 3;

    -GtkWidget-text-handle-width: 110px;
    -GtkWidget-text-handle-height: 110px;
}

*:disabled {
    color: @panel_grey;
}

/* Backgrounds and windows */

window {
    background: @panel_grey;
    color: @black;
}

dialog {
    background: @black;
    color: @white;
}

introwindow {
    background: @white;
    color: @black;
}

label, label:disabled {
    background: transparent;
}

/* Buttons */

button {
    ${ border = max(0, my_ceil((3*subcell_size/2.0 - icon_small / 2.0))) }
    padding: $(border)px $(border)px $(border)px $(border)px;
    border-width: $(thickness)px;
    border-color: @button_grey;
    border-style: solid;
    border-radius: $(2*subcell_size)px;
    background: @button_grey;
    color: @white;
}

button:focus {
    border-color: @white;
    color: @white;
}

button:active {
    background: @white;
    color: @black;
}

button:disabled {
    background: transparent;
}

button:active:focus {
    color: @black;
    border-color: @button_grey;
}

/* Linked boxes (eg. combobox entries) */

box.linked *:not(:first-child):not(:last-child) {
    border-radius: 0;
}

box.linked *:first-child:not(:last-child) {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
}

box.linked *:not(:first-child):last-child {
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
}

/* Spin buttons */

spinbutton button {
    background: @button_grey;
    border-style: solid;
    border-radius: 0;
}

spinbutton.horizontal button:last-child {
    border-radius: 0 $(2*subcell_size)px $(2*subcell_size)px 0;
}

spinbutton.vertical button:first-child {
    border-radius: $(2*subcell_size)px $(2*subcell_size)px 0 0;
    border-width: $(thickness)px $(thickness)px 0 $(thickness)px;
    border-style: solid;
}

spinbutton.vertical button:last-child {
    border-radius: 0 0 $(2*subcell_size)px $(2*subcell_size)px;
    border-width: 0 $(thickness)px $(thickness)px $(thickness)px;
    border-style: solid;
}

spinbutton button:active {
    background: @black;
}

spinbutton button:disabled {
    background: @selection_grey;
}

/* Toggle buttons */

button:checked {
    background: @white;
    color: @black;
}

/* Entries and views (textview, treeview) */

.view,
textview text {  /* Setting a textview to background white makes it black,
                    unless you only style the text css node */
    border-width: 0px;
    border-style: none;
    border-radius: 0px;
    padding: 0px;
    background: @white;
    color: @black;
}

treeview header button,
treeview header button:hover:active {
    border-radius: 0px;
    background: @button_grey;
    border-width: 0px;
    color: @white;
}

/* FIXME: treeview row css nodes aren't a thing

    $[if treeview_pseudo_element] GtkTreeView row:even
    $[else] GtkTreeView row:nth-child(even)
    $[end if] {
        background: @row_even;
    }

    $[if treeview_pseudo_element] GtkTreeView row:odd
    $[else] GtkTreeView row:nth-child(odd)
    $[end if] {
        background: @row_odd;
    }
*/

entry {
    border-radius: $(2 * subcell_size)px;
    border-width: $(thickness)px;
    border-color: @text_field_grey;
    border-style: solid;
    background: @text_field_grey;
    color: @black;
    ${ entry_ythickness = my_ceil(0.2 * (subcell_size*3.0/2.0 - thickness) + thickness) }
    ${ entry_xthickness = my_ceil(0.32 * (subcell_size*3.0/2.0 - thickness) + thickness) }
    padding: $(2 * max(my_ceil((3*subcell_size - font_height - entry_ythickness*2)/2.0),0))px $(2 * max(subcell_size - entry_xthickness, 0))px $(2 * max(my_floor((3*subcell_size - font_height - entry_ythickness*2)/2.0), 0))px $(2 * max(subcell_size - entry_xthickness, 0))px;
}

entry image {
    /* Default padding is too large and causes toolbar height expansion */
    margin: $(default_padding-1)px;
}

toolitem entry {
    margin: $(subcell_size)px;
}

entry progressbar {
    border-radius: $(2 * subcell_size)px;
    border-width: $(thickness)px;
    background: @selection_grey;
}

entry:focus {
    background: @white;
}

toolbar entry:focus {
    border-color: @white;
}

entry:disabled {
    background: @button_grey;
    border-color: @button_grey;
}

treeview:selected {
    background: @panel_grey;
    color: @black;
}

entry:selected,
entry:selected:focus {
    background: @selection_grey;
    color: @black;
}

entry:selected,
entry:selected:focus {
    border-color: @selection_grey;
}

selection {
    background: @selected_bg_color;
    color: @selected_fg_color;
}

/* Frames */

frame {
    border-style: solid;
    border-color: @selection_grey;
    border-width: $(thickness)px;
    border-radius: 0;
    padding: $(default_padding)px;
}

frame.journal-preview-box {
    border-color: @button_grey;
}

/* Combo boxes */

combobox {
    color: @white;
}

/* What does this do?
    combobox .menu.button {
        border-color: transparent;
        border-radius: 0px;
        border-style: none;
        background: transparent;
        color: @white;
    }
*/

combobox menu {
    -GtkWidget-scroll-arrow-hlength: $(my_floor(2.5 * subcell_size));
    -GtkWidget-scroll-arrow-vlength: $(my_floor(2.5 * subcell_size));
}

/* Notebooks */

notebook {
    background: @selection_grey;
    color: @black;
    padding: 0px;
    -GtkNotebook-tab-overlap: -2;
    -GtkNotebook-tab-curvature: $default_padding;
    -GtkWidget-scroll-arrow-hlength: $(my_floor(2.5 * subcell_size));
    -GtkWidget-scroll-arrow-vlength: $(my_floor(2.5 * subcell_size));
}

notebook arrow {
    color: @white;
}

notebook tab {
    background: @selection_grey;
}

/* Setting white color to the tab labels using only the previous rule */
/* doesn't work, so we have to set white color to the GtkLabel, and make */
/* sure the buttons get black color in the next two rules: */
notebook tab label {
    color: @white;
    padding: $(subcell_size)px 0;
}

notebook tab button label {
    color: @black;
}

notebook tab:checked {
    background: @toolbar_grey;
}

notebook tab button {
    border-radius: $(toolbutton_padding)px;
}

/* Browse Widgets */

BrowseSearchWindow treeview {
    background: @black;
    color: @white;
    border-color: @button_grey;
    border-width: 0 $(thickness)px $(thickness)px $(thickness)px;
    border-style: solid;
}

/* Control panel */

cpanelsectionview {
    background: @white;
    color: @black;
}

/* TODO:  this should only effect the control panel */
controlpanel image:disabled {
    opacity: $(disabled_opacity);
}

/* Alert */

alert {
    background: @black;
    color: @white;
}

alert *:disabled {
    background: @black;
}

button timeouticon label,
button timeouticon label:hover {
    background: @white;
    color: @button_grey;
    border-radius: $(2 * subcell_size)px;
}

button:active timeouticon label {
    background: @toolbar_grey;
    color: @white;
}

/* Tray */

htray, vtray {
    background: @toolbar_grey;
}

htray * , vtray * { background: @toolbar_grey;}

/* Menus and palettes */

palette,
popover {
    border: $(thickness)px solid @button_grey;
    background: @black;
    color: @white;
}

palette .view {
    color: @black;
}

SugarPaletteMenuWidget {
    background: @black;
}

SugarPaletteMenuWidget * {
    color: @white;
}

SugarPaletteWindow SugarGroupBox {
    background: @toolbar_grey;
    color: @white;
}

SugarPaletteWindow SugarGroupBox *:disabled {
    background: @toolbar_grey;
}

menu {
    background: @black;
    color: @white;

    -GtkMenu-scroll-arrow-vlength: $(my_floor(subcell_size/0.7 + 2*thickness));
    /* This means the outline of the submenu overlaps with a palette.
     * However in the case of two normal menus, they are next to each other.
     * It is not possible to be smarter about this, because the style comes from
     * the submenu. */
    -GtkMenu-horizontal-offset :  -$(line_width)px;
    -GtkMenu-vertical-offset   : 0;

    padding: 0px;

    border: $(thickness)px solid @button_grey;
}

menuitem {
    padding: $(subcell_size)px $((subcell_size * 3 - font_height) / 2)px;
}

menuitem:hover,
menuitem:hover {
    background: @button_grey;
}

menuitem separator {
    padding: 0;
}

tooltip {
    background: @black;
    border-style: solid;
    border-width: $(thickness)px;
    border-color: @button_grey;
}

tooltip * {
    color: @white;
}

/* Scrollbars */

scrollbar {
    -GtkRange-slider-width: $(subcell_size + 2*thickness);
    -GtkRange-trough-border: 0;
    -GtkRange-stepper-size: 0;
    -GtkScrollbar-min-slider-length: $(3*subcell_size);
    -GtkScrollbar-has-forward-stepper: 0;
    -GtkScrollbar-has-backward-stepper: 0;
    -GtkScrollbar-has-secondary-forward-stepper: 0;
    -GtkScrollbar-has-secondary-backward-stepper: 0;
}

scrollbar trough {
    background: @button_grey;
    border-width: 0px;
}

scrollbar slider {
    background: @white;
    border-radius: $(2*subcell_size)px;
    border-width: $(thickness)px;
    border-color: @button_grey;
    border-style: solid;
}

scrollbar slider:active {
    background: @text_field_grey;
}

/* Progress bars */

progressbar progress {
    background: @white;
    border-color: @button_grey;
    border-radius: $(subcell_size)px;
    border-style: solid;
    border-width: $(thickness)px;
}

progressbar trough {
    background: @selection_grey;
    border-style: solid;
    border-radius: $(subcell_size)px;
    border-color: @button_grey;
    border-width: $(thickness)px;
}

toolbar progressbar trough,
palette progressbar trough {
    background: @black;
}

/* Separators */

separator {
    /*border-top: $(thickness)px solid @button_grey;*/
    background-color: @button_grey;
}

/* Tool buttons */

toolbar,
toolbarbox {
    padding: 0;
    background: @toolbar_grey;
    color: @white;
}

/* FIXME: I needed to add the margin in the gtk3.20 port, but that wasn't
          there in the code before.  I ended up having to reduce the border
          to 2px */
toolbutton button,
filtertoolbutton button {
    border-style: none;
    background: transparent;
    border-radius: $(toolbutton_padding)px;
    padding: $(toolbutton_padding - default_padding)px;
    margin: $(default_padding)px;
}

toolbutton button #gtk-toolbar-arrow {
    padding: 0 $(subcell_size + default_padding)px;
}

toolbutton button:disabled {
    opacity: $(disabled_opacity);
}

toolbutton button:hover {
    padding: $(toolbutton_padding - 2 - default_padding)px;
    border-width: 2px;
    border-style: solid;
    background-clip: padding-box;
}

toolbutton button:hover:not(:checked),
toolbutton button:hover:not(:checked) * {
    background: @black;
}

toolbutton button.radio:checked,
toolbutton button.radio:checked * {
    background: @button_grey;
    border-radius: $(toolbutton_padding)px;
}

toolbutton button.radio:checked:hover,
toolbutton button.radio:checked:hover * {
    background: @button_grey;
    border-color: @button_grey;
}

toolbutton button:active,
toolbutton button:active * {
    background: @button_grey;
    border-radius: $(toolbutton_padding)px;
}

palette scrolledwindow {
    background: @black;
}

toolbar combobox button {
    border-radius: $(2*subcell_size)px;
}

/* Scales */

scale {
    -GtkScale-slider-length: $scale_slider_width;
    -GtkRange-slider-width: $scale_slider_width;
}

scale highlight {
    background: @white;
    border-style: solid;
    border-color: @button_grey;
    border-width: $(thickness)px;
}

scale trough {
    background: @button_grey;
    border-style: solid;
    border-color: @button_grey;
    border-width: $(thickness)px;
    margin: $(scale_trough_margin)px 0;
}

scale.vertical trough {
    margin: 0 $(scale_trough_margin)px;
}

scale trough:focus {
    border-color: @white;
}

scale trough,
scale highlight {
    border-radius: $(2*subcell_size)px $(2*subcell_size)px;
}

scale slider,
scale slider:active {
    background: transparent;
}

scale slider {
    background-image: url("assets/scale-slider.svg");
}

scale slider:active {
    background-image: url("assets/scale-slider-active.svg");
}

/* Radio and check buttons */

check:hover {
    background: alpha(@theme_base_color, 0.0);
}

toolbar check,
palette check {
    color: @theme_base_color;
    border: 1px solid @theme_base_color;
}

radio,
radio row:selected,
radio row:selected:focus {
    -gtk-icon-source: url("assets/radio.svg");
    background: alpha(@theme_base_color, 0.0);
}

radio:selected,
radio:selected row:selected,
radio:selected row:selected:focus {
    -gtk-icon-source: url("assets/radio-selected.svg");
}

radio:active,
radio row:selected:active,
radio row:selected:focus:active {
    -gtk-icon-source: url("assets/radio-active.svg");
}

radio:checked,
radio row:selected:checked,
radio row:selected:focus:checked {
   -gtk-icon-source: url("assets/radio-active.svg");
}

radio:active:selected,
radio:selected row:selected:active,
radio:selected row:selected:focus:active {
    -gtk-icon-source: url("assets/radio-active-selected.svg");
}

radio:checked:selected,
radio:selected row:selected:checked,
radio:selected row:selected:focus:checked {
    -gtk-icon-source: url("assets/radio-active-selected.svg");
}

check,
check row:selected,
check row:selected:focus {
    -gtk-icon-source: url("assets/checkbox-unchecked.svg");
    background: alpha(@theme_base_color, 0.0);
}

check:selected,
check:selected row:selected,
check:selected row:selected:focus {
    -gtk-icon-source: url("assets/checkbox-unchecked-selected.svg");
}

check:active,
check row:selected:active,
check row:selected:focus:active {
    -gtk-icon-source: url("assets/checkbox-checked.svg");
}

check:checked,
check row:selected:checked,
check row:selected:focus:checked {
    -gtk-icon-source: url("assets/checkbox-checked.svg");
}

check:active:selected,
check:selected row:selected:active,
check:selected row:selected:focus:active {
    -gtk-icon-source: url("assets/checkbox-checked-selected.svg");
}

check:checked:selected,
check:selected row:selected:checked,
check:selected row:selected:focus:checked {
    background-image: url("assets/checkbox-checked-selected.svg");
    -gtk-icon-source: url("assets/checkbox-checked-selected.svg");
}

/* Tool items */

toolitem {
    /* arrow in the toolbarbox */
    color: @white;
}

.palette-down,
.toolbar-down {
    /* outline of the toolbarbutton when palette is expanded */
    border-style: solid;
    border-width: 2px;
    border-color: @button_grey;
}

/* GtkImage */

image {
    background: transparent;
}

/* Sugar Frame Window */

framewindow {
    background: @toolbar_grey;
}

/* Sugar Canvas icon */

canvasicon {
    border-color: transparent;
    border-radius: $(4 * thickness)px;
    border-width: 2px;
    border-style: solid;
    background: transparent;
}

canvasicon:hover {
    border-color: @zoom_views_prelight;
    background: @zoom_views_prelight;
}

canvasicon.toggle-press {
    border-color: @zoom_views_active;
    background: @zoom_views_active;
}

/* Sugar CellRenderer Icons */

.cell.sugar-icon-cell {
    background: transparent;
    border-radius: $(4 * thickness)px;
    border-color: @white;
    border-width: $(thickness)px;
    border-style: solid;
}

.cell.sugar-icon-cell:hover {
    background: @zoom_views_prelight;
}

.cell.sugar-icon-cell:active {
    background: @zoom_views_active;
}

/* CellRendererProgress */

.cell.progressbar, .cell.trough {
    border-style: solid;
    border-width: $(thickness)px;
    border-color: @selection_grey;
    border-radius: $(2*subcell_size)px;
}

.cell.progressbar {
    background: @white;
}

.cell.trough {
    background: @text_field_grey;
}

/* Text cursor handles */

cursor-handle.top,
cursor-handle.bottom {
    background: transparent;
    border-radius: 10px;
    border-width: $(thickness)px;
    border-color: @panel_grey;
    border-style: solid;
}

cursor-handle.bottom {
    -gtk-icon-source: url("assets/cursor-handle-bottom.svg");
}

cursor-handle.top {
    -gtk-icon-source: url("assets/cursor-handle-top.svg");
}

cursor-handle.insertion-cursor {
    -gtk-icon-source: url("assets/cursor-handle-insertion.svg");
}

/* Application specific properties */

EvView {
    background: @panel_grey;
}

EvView:selected,
ApDocView:selected {
    background: @selection_grey;
}

${
import os
import math

gtk_major, gtk_minor, gtk_patch = map(int, gtk.split('.'))
treeview_pseudo_element = gtk_major >= 3 and gtk_minor >= 16

def my_floor(num):
    return int(math.floor(num))

def my_ceil(num):
    return int(math.ceil(num))

# Should we set the line width in the engine to 2.25, and draw non pixel aligned lines?
# Are these already the correct sizes for the XO?

# These sizes need to be sanity checked ...
if scaling == "100":
    xo = True
    line_width = 2.0        # 2.25px, rounded down
    thick_line_width = 3.5  # 3.5
    subcell_size = 15
    icon_base = 11
    bullet_size = 9.5
    font_height = 24
    default_padding = 6
    toolbutton_padding = 10
    radio_size = 26
    scale_trough_margin = 8
else: # About 72% of the XO size, adjusted so that eg. toolbuttons work
    xo = False
    line_width = 2.0            # 1.62 rounded up
    thick_line_width = 3.0      # 2.52
    subcell_size = 11           # 10.8
    icon_base = 8               # 7.92
    bullet_size = 6.5           # 6.84
    # This is a guess on the font size (Sans 10 at 96 DPI)
    font_height = 17
    default_padding = 4         # 4.32
    toolbutton_padding = 7      # 7.68
    radio_size = 18             # 18.72
    scale_trough_margin = 6     # 5.76

scale_slider_width = my_floor(2 * subcell_size + line_width)
thickness = my_ceil(line_width)

icon_small = icon_base * 3
icon_large = icon_base * 5

disabled_opacity = 0.5

}

* {
    -sugar-focus-line: @white;

    /* 0.05 works good for both the sugar and sugar-xo themes */
    -GtkWidget-cursor-aspect-ratio: 0.05;

    -GtkWidget-wide-separators: true;
    -GtkWidget-separator-height: $thickness;
    -GtkWidget-separator-width: $thickness;

    -GtkWidget-scroll-arrow-hlength: $subcell_size;
    -GtkWidget-scroll-arrow-vlength: $subcell_size;

    -GtkRange-activate-slider: 1;

    -GtkScrolledWindow-scrollbar-spacing: 0;

    -GtkExpander-expander-size: $font_height;
    -GtkExpander-expander-spacing: 2;

    -GtkTreeView-expander-size: $font_height;

    -GtkArrow-arrow-size: 1.0;

    -GtkToolbar-space-size: $(2*subcell_size);

    -GtkProgressBar-min-horizontal-bar-height: $subcell_size;
    -GtkProgressBar-min-vertical-bar-width: $subcell_size;

    -GtkCheckButton-indicator-size: $radio_size;
    -GtkCheckButton-indicator-spacing: 3;

    -GtkWidget-text-handle-width: 110px;
    -GtkWidget-text-handle-height: 110px;
}

*:disabled {
    color: @panel_grey;
}

/* Backgrounds and windows */

window {
    background: @panel_grey;
    color: @black;
}

dialog {
    background: @black;
    color: @white;
}

introwindow {
    background: @white;
    color: @black;
}

label, label:disabled {
    background: transparent;
}

/* Buttons */

button {
    ${ border = max(0, my_ceil((3*subcell_size/2.0 - icon_small / 2.0))) }
    padding: $(border)px $(border)px $(border)px $(border)px;
    border-width: $(thickness)px;
    border-color: @button_grey;
    border-style: solid;
    border-radius: $(2*subcell_size)px;
    background: @button_grey;
    color: @white;
}

button:focus {
    border-color: @white;
    color: @white;
}

button:active {
    background: @white;
    color: @black;
}

button:disabled {
    background: transparent;
}

button:active:focus {
    color: @black;
    border-color: @button_grey;
}

/* Spin buttons */

spinbutton button {
    background: @button_grey;
    border-style: solid;
    border-radius: 0;
}

spinbutton.horizontal button:last-child {
    border-radius: 0 $(2*subcell_size)px $(2*subcell_size)px 0;
}

spinbutton.vertical button:first-child {
    border-radius: $(2*subcell_size)px $(2*subcell_size)px 0 0;
    border-width: $(thickness)px $(thickness)px 0 $(thickness)px;
    border-style: solid;
}

spinbutton.vertical button:last-child {
    border-radius: 0 0 $(2*subcell_size)px $(2*subcell_size)px;
    border-width: 0 $(thickness)px $(thickness)px $(thickness)px;
    border-style: solid;
}

spinbutton button:active {
    background: @black;
}

spinbutton button:disabled {
    background: @selection_grey;
}

/* Toggle buttons */

button:checked {
    background: @white;
    color: @black;
}

/* Entries and views (textview, treeview) */

.view,
textview text {  /* Setting a textview to background white makes it black,
                    unless you only style the text css node */
    border-width: 0px;
    border-style: none;
    border-radius: 0px;
    padding: 0px;
    background: @white;
    color: @black;
}

treeview header button,
treeview header button:hover:active {
    border-radius: 0px;
    background: @button_grey;
    border-width: 0px;
    color: @white;
}

/* FIXME: treeview row css nodes aren't a thing

    $[if treeview_pseudo_element] GtkTreeView row:even
    $[else] GtkTreeView row:nth-child(even)
    $[end if] {
        background: @row_even;
    }

    $[if treeview_pseudo_element] GtkTreeView row:odd
    $[else] GtkTreeView row:nth-child(odd)
    $[end if] {
        background: @row_odd;
    }
*/

entry {
    border-radius: $(2 * subcell_size)px;
    border-width: $(thickness)px;
    border-color: @text_field_grey;
    border-style: solid;
    background: @text_field_grey;
    color: @black;
    ${ entry_ythickness = my_ceil(0.2 * (subcell_size*3.0/2.0 - thickness) + thickness) }
    ${ entry_xthickness = my_ceil(0.32 * (subcell_size*3.0/2.0 - thickness) + thickness) }
    padding: $(2 * max(my_ceil((3*subcell_size - font_height - entry_ythickness*2)/2.0),0))px $(2 * max(subcell_size - entry_xthickness, 0))px $(2 * max(my_floor((3*subcell_size - font_height - entry_ythickness*2)/2.0), 0))px $(2 * max(subcell_size - entry_xthickness, 0))px;
}

entry image {
    /* Default padding is too large and causes toolbar height expansion */
    margin: $(default_padding-1)px;
}

toolitem entry {
    margin: $(subcell_size)px;
}

entry progressbar {
    border-radius: $(2 * subcell_size)px;
    border-width: $(thickness)px;
    background: @selection_grey;
}

entry:focus {
    background: @white;
}

toolbar entry:focus {
    border-color: @white;
}

entry:disabled {
    background: @button_grey;
    border-color: @button_grey;
}

treeview:selected {
    background: @panel_grey;
    color: @black;
}

entry:selected,
entry:selected:focus {
    background: @selection_grey;
    color: @black;
}

entry:selected,
entry:selected:focus {
    border-color: @selection_grey;
}

selection {
    background: @selected_bg_color;
    color: @selected_fg_color;
}

/* Frames */

frame {
    border-style: solid;
    border-color: @selection_grey;
    border-width: $(thickness)px;
    border-radius: 0;
    padding: $(default_padding)px;
}

frame.journal-preview-box {
    border-color: @button_grey;
}

/* Combo boxes */

combobox {
    color: @white;
}

/* What does this do?
    combobox .menu.button {
        border-color: transparent;
        border-radius: 0px;
        border-style: none;
        background: transparent;
        color: @white;
    }
*/

combobox menu {
    -GtkWidget-scroll-arrow-hlength: $(my_floor(2.5 * subcell_size));
    -GtkWidget-scroll-arrow-vlength: $(my_floor(2.5 * subcell_size));
}

/* Notebooks */

notebook {
    background: @selection_grey;
    color: @black;
    padding: 0px;
    -GtkNotebook-tab-overlap: -2;
    -GtkNotebook-tab-curvature: $default_padding;
    -GtkWidget-scroll-arrow-hlength: $(my_floor(2.5 * subcell_size));
    -GtkWidget-scroll-arrow-vlength: $(my_floor(2.5 * subcell_size));
}

notebook arrow {
    color: @white;
}

notebook tab {
    background: @selection_grey;
}

/* Setting white color to the tab labels using only the previous rule */
/* doesn't work, so we have to set white color to the GtkLabel, and make */
/* sure the buttons get black color in the next two rules: */
notebook tab label {
    color: @white;
    padding: $(subcell_size)px 0;
}

notebook tab button label {
    color: @black;
}

notebook tab:checked {
    background: @toolbar_grey;
}

notebook tab button {
    border-radius: $(toolbutton_padding)px;
}

/* Browse Widgets */

BrowseSearchWindow treeview {
    background: @black;
    color: @white;
    border-color: @button_grey;
    border-width: 0 $(thickness)px $(thickness)px $(thickness)px;
    border-style: solid;
}

/* Control panel */

cpanelsectionview {
    background: @white;
    color: @black;
}

/* TODO:  this should only effect the control panel */
controlpanel image:disabled {
    opacity: $(disabled_opacity);
}

/* Alert */

alert {
    background: @black;
    color: @white;
}

alert *:disabled {
    background: @black;
}

button timeouticon label,
button timeouticon label:hover {
    background: @white;
    color: @button_grey;
    border-radius: $(2 * subcell_size)px;
}

button:active timeouticon label {
    background: @toolbar_grey;
    color: @white;
}

/* Tray */

htray, vtray {
    background: @toolbar_grey;
}

htray * , vtray * { background: @toolbar_grey;}

/* Menus and palettes */

palette,
popover {
    border: $(thickness)px solid @button_grey;
    background: @black;
    color: @white;
}

palette .view {
    color: @black;
}

SugarPaletteMenuWidget {
    background: @black;
}

SugarPaletteMenuWidget * {
    color: @white;
}

SugarPaletteWindow SugarGroupBox {
    background: @toolbar_grey;
    color: @white;
}

SugarPaletteWindow SugarGroupBox *:disabled {
    background: @toolbar_grey;
}

menu {
    background: @black;
    color: @white;

    -GtkMenu-scroll-arrow-vlength: $(my_floor(subcell_size/0.7 + 2*thickness));
    /* This means the outline of the submenu overlaps with a palette.
     * However in the case of two normal menus, they are next to each other.
     * It is not possible to be smarter about this, because the style comes from
     * the submenu. */
    -GtkMenu-horizontal-offset :  -$(line_width)px;
    -GtkMenu-vertical-offset   : 0;

    padding: 0px;

    border: $(thickness)px solid @button_grey;
}

menuitem {
    padding: $(subcell_size)px $((subcell_size * 3 - font_height) / 2)px;
}

menuitem:hover,
menuitem:hover {
    background: @button_grey;
}

menuitem separator {
    padding: 0;
}

tooltip {
    background: @black;
    border-style: solid;
    border-width: $(thickness)px;
    border-color: @button_grey;
}

tooltip * {
    color: @white;
}

/* Scrollbars */

scrollbar {
    -GtkRange-slider-width: $(subcell_size + 2*thickness);
    -GtkRange-trough-border: 0;
    -GtkRange-stepper-size: 0;
    -GtkScrollbar-min-slider-length: $(3*subcell_size);
    -GtkScrollbar-has-forward-stepper: 0;
    -GtkScrollbar-has-backward-stepper: 0;
    -GtkScrollbar-has-secondary-forward-stepper: 0;
    -GtkScrollbar-has-secondary-backward-stepper: 0;
}

scrollbar trough {
    background: @button_grey;
    border-width: 0px;
}

scrollbar slider {
    background: @white;
    border-radius: $(2*subcell_size)px;
    border-width: $(thickness)px;
    border-color: @button_grey;
    border-style: solid;
}

scrollbar slider:active {
    background: @text_field_grey;
}

/* Progress bars */

progressbar progress {
    background: @white;
    border-color: @button_grey;
    border-radius: $(subcell_size)px;
    border-style: solid;
    border-width: $(thickness)px;
}

progressbar trough {
    background: @selection_grey;
    border-style: solid;
    border-radius: $(subcell_size)px;
    border-color: @button_grey;
    border-width: $(thickness)px;
}

toolbar progressbar trough,
palette progressbar trough {
    background: @black;
}

/* Separators */

separator {
    /*border-top: $(thickness)px solid @button_grey;*/
    background-color: @button_grey;
}

/* Tool buttons */

toolbar,
toolbarbox {
    padding: 0;
    background: @toolbar_grey;
    color: @white;
}

/* FIXME: I needed to add the margin in the gtk3.20 port, but that wasn't
          there in the code before.  I ended up having to reduce the border
          to 2px */
toolbutton button,
filtertoolbutton button {
    border-style: none;
    background: transparent;
    border-radius: $(toolbutton_padding)px;
    padding: $(toolbutton_padding - default_padding)px;
    margin: $(default_padding)px;
}

toolbutton button #gtk-toolbar-arrow {
    padding: 0 $(subcell_size + default_padding)px;
}

toolbutton button:disabled {
    opacity: $(disabled_opacity);
}

toolbutton button:hover {
    padding: $(toolbutton_padding - 2 - default_padding)px;
    border-width: 2px;
    border-style: solid;
    background-clip: padding-box;
}

toolbutton button:hover:not(:checked),
toolbutton button:hover:not(:checked) * {
    background: @black;
}

toolbutton button.radio:checked,
toolbutton button.radio:checked * {
    background: @button_grey;
    border-radius: $(toolbutton_padding)px;
}

toolbutton button.radio:checked:hover,
toolbutton button.radio:checked:hover * {
    background: @button_grey;
    border-color: @button_grey;
}

toolbutton button:active,
toolbutton button:active * {
    background: @button_grey;
    border-radius: $(toolbutton_padding)px;
}

palette scrolledwindow {
    background: @black;
}

toolbar combobox button {
    border-radius: $(2*subcell_size)px;
}

/* Scales */

scale {
    -GtkScale-slider-length: $scale_slider_width;
    -GtkRange-slider-width: $scale_slider_width;
}

scale highlight {
    background: @white;
    border-style: solid;
    border-color: @button_grey;
    border-width: $(thickness)px;
}

scale trough {
    background: @button_grey;
    border-style: solid;
    border-color: @button_grey;
    border-width: $(thickness)px;
    margin: $(scale_trough_margin)px 0;
}

scale.vertical trough {
    margin: 0 $(scale_trough_margin)px;
}

scale trough:focus {
    border-color: @white;
}

scale trough,
scale highlight {
    border-radius: $(2*subcell_size)px $(2*subcell_size)px;
}

scale slider,
scale slider:active {
    background: transparent;
}

scale slider {
    background-image: url("assets/scale-slider.svg");
}

scale slider:active {
    background-image: url("assets/scale-slider-active.svg");
}

/* Radio and check buttons */

check:hover {
    background: alpha(@theme_base_color, 0.0);
}

toolbar check,
palette check {
    color: @theme_base_color;
    border: 1px solid @theme_base_color;
}

radio,
radio row:selected,
radio row:selected:focus {
    -gtk-icon-source: url("assets/radio.svg");
    background: alpha(@theme_base_color, 0.0);
}

radio:selected,
radio:selected row:selected,
radio:selected row:selected:focus {
    -gtk-icon-source: url("assets/radio-selected.svg");
}

radio:active,
radio row:selected:active,
radio row:selected:focus:active {
    -gtk-icon-source: url("assets/radio-active.svg");
}

radio:checked,
radio row:selected:checked,
radio row:selected:focus:checked {
   -gtk-icon-source: url("assets/radio-active.svg");
}

radio:active:selected,
radio:selected row:selected:active,
radio:selected row:selected:focus:active {
    -gtk-icon-source: url("assets/radio-active-selected.svg");
}

radio:checked:selected,
radio:selected row:selected:checked,
radio:selected row:selected:focus:checked {
    -gtk-icon-source: url("assets/radio-active-selected.svg");
}

check,
check row:selected,
check row:selected:focus {
    -gtk-icon-source: url("assets/checkbox-unchecked.svg");
    background: alpha(@theme_base_color, 0.0);
}

check:selected,
check:selected row:selected,
check:selected row:selected:focus {
    -gtk-icon-source: url("assets/checkbox-unchecked-selected.svg");
}

check:active,
check row:selected:active,
check row:selected:focus:active {
    -gtk-icon-source: url("assets/checkbox-checked.svg");
}

check:checked,
check row:selected:checked,
check row:selected:focus:checked {
    -gtk-icon-source: url("assets/checkbox-checked.svg");
}

check:active:selected,
check:selected row:selected:active,
check:selected row:selected:focus:active {
    -gtk-icon-source: url("assets/checkbox-checked-selected.svg");
}

check:checked:selected,
check:selected row:selected:checked,
check:selected row:selected:focus:checked {
    background-image: url("assets/checkbox-checked-selected.svg");
    -gtk-icon-source: url("assets/checkbox-checked-selected.svg");
}

/* Tool items */

toolitem {
    /* arrow in the toolbarbox */
    color: @white;
}

.palette-down,
.toolbar-down {
    /* outline of the toolbarbutton when palette is expanded */
    border-style: solid;
    border-width: 2px;
    border-color: @button_grey;
}

/* GtkImage */

image {
    background: transparent;
}

/* Sugar Frame Window */

framewindow {
    background: @toolbar_grey;
}

/* Sugar Canvas icon */

canvasicon {
    border-color: transparent;
    border-radius: $(4 * thickness)px;
    border-width: 2px;
    border-style: solid;
    background: transparent;
}

canvasicon:hover {
    border-color: @zoom_views_prelight;
    background: @zoom_views_prelight;
}

canvasicon.toggle-press {
    border-color: @zoom_views_active;
    background: @zoom_views_active;
}

/* Sugar CellRenderer Icons */

.cell.sugar-icon-cell {
    background: transparent;
    border-radius: $(4 * thickness)px;
    border-color: @white;
    border-width: $(thickness)px;
    border-style: solid;
}

.cell.sugar-icon-cell:hover {
    background: @zoom_views_prelight;
}

.cell.sugar-icon-cell:active {
    background: @zoom_views_active;
}

/* CellRendererProgress */

.cell.progressbar, .cell.trough {
    border-style: solid;
    border-width: $(thickness)px;
    border-color: @selection_grey;
    border-radius: $(2*subcell_size)px;
}

.cell.progressbar {
    background: @white;
}

.cell.trough {
    background: @text_field_grey;
}

/* Text cursor handles */

cursor-handle.top,
cursor-handle.bottom {
    background: transparent;
    border-radius: 10px;
    border-width: $(thickness)px;
    border-color: @panel_grey;
    border-style: solid;
}

cursor-handle.bottom {
    -gtk-icon-source: url("assets/cursor-handle-bottom.svg");
}

cursor-handle.top {
    -gtk-icon-source: url("assets/cursor-handle-top.svg");
}

cursor-handle.insertion-cursor {
    -gtk-icon-source: url("assets/cursor-handle-insertion.svg");
}

/* Application specific properties */

EvView {
    background: @panel_grey;
}

EvView:selected,
ApDocView:selected {
    background: @selection_grey;
}


Comment out labels

Comment out labels

@[if packages]@
@# # label @group packages
@# LABEL @(' \\\n      '.join('org.osrfoundation.{name}.sha256={sha256}'.format(**p) for p in packages))@
@#
@#
# install @group packages
RUN apt-get update && apt-get install -y --no-install-recommends \
    @(' \\\n    '.join('{name}{version}'.format(**p) for p in packages))@  \
    && rm -rf /var/lib/apt/lists/*
@[end if]

@[if packages]@
# label @group packages
LABEL @(' \\\n      '.join('org.osrfoundation.{name}.sha256={sha256}'.format(**p) for p in packages))@

# install @group packages
RUN apt-get update && apt-get install -y --no-install-recommends \
    @(' \\\n    '.join('{name}{version}'.format(**p) for p in packages))@  \
    && rm -rf /var/lib/apt/lists/*
@[end if]


remove duplicate regex for failed case (should be implicit)

<project>
  <actions/>
  <description>Generated at @ESCAPE(now_str) from template '@ESCAPE(template_name)'</description>
@(SNIPPET(
    'log-rotator',
    days_to_keep=100,
    num_to_keep=100,
))@
  <keepDependencies>false</keepDependencies>
  <properties>
@(SNIPPET(
    'property_parameters-definition',
    parameters=[
        {
            'type': 'string',
            'name': 'subfolder',
            'description': '',
            'default_value': None,
        },
        {
            'type': 'string',
            'name': 'debian_package_name',
            'description': '',
            'default_value': None,
        },
    ],
))@
@(SNIPPET(
    'property_requeue-job',
))@
@(SNIPPET(
    'property_disk-usage',
))@
  </properties>
@(SNIPPET(
    'scm_git',
    url='https://github.com/ros-infrastructure/reprepro-updater.git',
    refspec='refactor',
    relative_target_dir='reprepro-updater',
))@
  <assignedNode>building_repository</assignedNode>
  <canRoam>false</canRoam>
  <disabled>false</disabled>
  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
  <triggers/>
  <concurrentBuild>false</concurrentBuild>
  <builders>
@(SNIPPET(
    'builder_shell',
    script='\n'.join([
        'echo "# BEGIN SECTION: import debian package"',
        'export PYTHONPATH=$WORKSPACE/reprepro-updater/src:$PYTHONPATH',
        'python -u $WORKSPACE/reprepro-updater/scripts/include_folder.py --folder /var/repos/ubuntu/building/queue/$subfolder --package $debian_package_name --delete-folder --commit',
        'echo "# END SECTION"',
    ]),
))@
  </builders>
  <publishers>
@(SNIPPET(
    'publisher_description-setter',
    regexp='Imported package: (\S+)',
    regexp_for_failed='',
))@
@(SNIPPET(
    'publisher_mailer',
    recipients=notify_emails,
    dynamic_recipients=[],
    send_to_individuals=False,
))@
  </publishers>
  <buildWrappers>
@(SNIPPET(
    'build-wrapper_timestamper',
))@
  </buildWrappers>
</project>

<project>
  <actions/>
  <description>Generated at @ESCAPE(now_str) from template '@ESCAPE(template_name)'</description>
@(SNIPPET(
    'log-rotator',
    days_to_keep=100,
    num_to_keep=100,
))@
  <keepDependencies>false</keepDependencies>
  <properties>
@(SNIPPET(
    'property_parameters-definition',
    parameters=[
        {
            'type': 'string',
            'name': 'subfolder',
            'description': '',
            'default_value': None,
        },
        {
            'type': 'string',
            'name': 'debian_package_name',
            'description': '',
            'default_value': None,
        },
    ],
))@
@(SNIPPET(
    'property_requeue-job',
))@
@(SNIPPET(
    'property_disk-usage',
))@
  </properties>
@(SNIPPET(
    'scm_git',
    url='https://github.com/ros-infrastructure/reprepro-updater.git',
    refspec='refactor',
    relative_target_dir='reprepro-updater',
))@
  <assignedNode>building_repository</assignedNode>
  <canRoam>false</canRoam>
  <disabled>false</disabled>
  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
  <triggers/>
  <concurrentBuild>false</concurrentBuild>
  <builders>
@(SNIPPET(
    'builder_shell',
    script='\n'.join([
        'echo "# BEGIN SECTION: import debian package"',
        'export PYTHONPATH=$WORKSPACE/reprepro-updater/src:$PYTHONPATH',
        'python -u $WORKSPACE/reprepro-updater/scripts/include_folder.py --folder /var/repos/ubuntu/building/queue/$subfolder --package $debian_package_name --delete-folder --commit',
        'echo "# END SECTION"',
    ]),
))@
  </builders>
  <publishers>
@(SNIPPET(
    'publisher_description-setter',
    regexp='Imported package: (\S+)',
    regexp_for_failed='Imported package: (\S+)',
))@
@(SNIPPET(
    'publisher_mailer',
    recipients=notify_emails,
    dynamic_recipients=[],
    send_to_individuals=False,
))@
  </publishers>
  <buildWrappers>
@(SNIPPET(
    'build-wrapper_timestamper',
))@
  </buildWrappers>
</project>


spelling (#442)

spelling (#442)

<project>
  <actions/>
  <description>

      This job should not be aborted since reprepro will likely leave lockfiles behind!

Generated at @ESCAPE(now_str) from template '@ESCAPE(template_name)'</description>
  <keepDependencies>false</keepDependencies>
  <properties>
@(SNIPPET(
    'property_log-rotator',
    days_to_keep=100,
    num_to_keep=100,
))@
@(SNIPPET(
    'property_job-priority',
    priority=20,
))@
@(SNIPPET(
    'property_requeue-job',
))@
@(SNIPPET(
    'property_parameters-definition',
    parameters=[
        {
            'type': 'string',
            'name': 'config_file',
            'description': 'A specific yaml file or files to use as reprepro_config arguments. The default is the ros_bootstrap config. If unset it defaults to aggregating all yaml files in the directory defined by upstream_config in reprepro-updater.ini(not recommended)',
            'default_value': '/home/jenkins-slave/reprepro_config/ros_bootstrap.yaml',
        },
        {
            'type': 'boolean',
            'name': 'EXECUTE_IMPORT',
            'description': 'If this is not true, it will only do a dry run and print the expect import, but not execute.',
            'default_value': 'false',
        },
    ],
))@
  </properties>
@(SNIPPET(
    'scm_git',
    url='https://github.com/ros-infrastructure/reprepro-updater.git',
    branch_name='refactor',
    relative_target_dir='reprepro-updater',
    refspec=None,
))@
  <scmCheckoutRetryCount>2</scmCheckoutRetryCount>
  <assignedNode>building_repository</assignedNode>
  <canRoam>false</canRoam>
  <disabled>false</disabled>
  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
  <triggers/>
  <concurrentBuild>false</concurrentBuild>
  <builders>
@(SNIPPET(
    'builder_shell',
    script='\n'.join([
        'echo "# BEGIN SECTION: import debian packages"',
        'if [ "$EXECUTE_IMPORT" = "true" ]; then',
        '  export COMMIT_ARG="--commit"',
        'fi',
        'export PYTHONPATH=$WORKSPACE/reprepro-updater/src:$PYTHONPATH',
        'echo "# BEGIN SUBSECTION: import debian packages for ubuntu_building"',
        'python -u $WORKSPACE/reprepro-updater/scripts/import_upstream.py ubuntu_building $config_file $COMMIT_ARG',
        'echo "# END SUBSECTION"',
        'echo "# BEGIN SUBSECTION: import debian packages for ubuntu_testing"',
        'python -u $WORKSPACE/reprepro-updater/scripts/import_upstream.py ubuntu_testing $config_file $COMMIT_ARG',
        'echo "# END SUBSECTION"',
        'echo "# BEGIN SUBSECTION: import debian packages for ubuntu_main"',
        'python -u $WORKSPACE/reprepro-updater/scripts/import_upstream.py ubuntu_main $config_file $COMMIT_ARG',
        'echo "# END SUBSECTION"',
        'echo "# END SECTION"',
    ]),
))@
  </builders>
  <publishers>
@(SNIPPET(
    'publisher_mailer',
    recipients=recipients,
    dynamic_recipients=[],
    send_to_individuals=False,
))@
  </publishers>
  <buildWrappers>
@(SNIPPET(
    'build-wrapper_timestamper',
))@
  </buildWrappers>
</project>

<project>
  <actions/>
  <description>

      This job should not be aborted since reprepro will likely leave lockfile behind!

Generated at @ESCAPE(now_str) from template '@ESCAPE(template_name)'</description>
  <keepDependencies>false</keepDependencies>
  <properties>
@(SNIPPET(
    'property_log-rotator',
    days_to_keep=100,
    num_to_keep=100,
))@
@(SNIPPET(
    'property_job-priority',
    priority=20,
))@
@(SNIPPET(
    'property_requeue-job',
))@
@(SNIPPET(
    'property_parameters-definition',
    parameters=[
        {
            'type': 'string',
            'name': 'config_file',
            'description': 'A specific yaml file or files to use as reprepro_config arguments. The default is the ros_bootstrap config. If unset it defaults to aggregating all yaml files in the directory defined by upstream_config in reprepro-updater.ini(not recommended)',
            'default_value': '/home/jenkins-slave/reprepro_config/ros_bootstrap.yaml',
        },
        {
            'type': 'boolean',
            'name': 'EXECUTE_IMPORT',
            'description': 'If this is not true, it will only do a dry run and print the expect import, but not execute.',
            'default_value': 'false',
        },
    ],
))@
  </properties>
@(SNIPPET(
    'scm_git',
    url='https://github.com/ros-infrastructure/reprepro-updater.git',
    branch_name='refactor',
    relative_target_dir='reprepro-updater',
    refspec=None,
))@
  <scmCheckoutRetryCount>2</scmCheckoutRetryCount>
  <assignedNode>building_repository</assignedNode>
  <canRoam>false</canRoam>
  <disabled>false</disabled>
  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
  <triggers/>
  <concurrentBuild>false</concurrentBuild>
  <builders>
@(SNIPPET(
    'builder_shell',
    script='\n'.join([
        'echo "# BEGIN SECTION: import debian packages"',
        'if [ "$EXECUTE_IMPORT" = "true" ]; then',
        '  export COMMIT_ARG="--commit"',
        'fi',
        'export PYTHONPATH=$WORKSPACE/reprepro-updater/src:$PYTHONPATH',
        'echo "# BEGIN SUBSECTION: import debian packages for ubuntu_building"',
        'python -u $WORKSPACE/reprepro-updater/scripts/import_upstream.py ubuntu_building $config_file $COMMIT_ARG',
        'echo "# END SUBSECTION"',
        'echo "# BEGIN SUBSECTION: import debian packages for ubuntu_testing"',
        'python -u $WORKSPACE/reprepro-updater/scripts/import_upstream.py ubuntu_testing $config_file $COMMIT_ARG',
        'echo "# END SUBSECTION"',
        'echo "# BEGIN SUBSECTION: import debian packages for ubuntu_main"',
        'python -u $WORKSPACE/reprepro-updater/scripts/import_upstream.py ubuntu_main $config_file $COMMIT_ARG',
        'echo "# END SUBSECTION"',
        'echo "# END SECTION"',
    ]),
))@
  </builders>
  <publishers>
@(SNIPPET(
    'publisher_mailer',
    recipients=recipients,
    dynamic_recipients=[],
    send_to_individuals=False,
))@
  </publishers>
  <buildWrappers>
@(SNIPPET(
    'build-wrapper_timestamper',
))@
  </buildWrappers>
</project>


unset COMMAND so it doesn't pulled the setup_xxx.bat files.

REM generated from ros/env-hooks/10.ros.bat.em

REM scrub old ROS bin dirs, to avoid accidentally finding the wrong executables
set COMMAND=python -c "import os; print(os.pathsep.join([x for x in r'%PATH%'.split(os.pathsep) if not any([d for d in ['cturtle', 'diamondback', 'electric', 'fuerte'] if d in x])]))"
rem Need the delims= line here to ensure that it reads with eol delimiters, not space.
for /f "delims=" %%i in ('%COMMAND%') do set PATH=%%i

set ROS_DISTRO=groovy

REM python function to generate ROS package path based on all parent workspaces (prepends the separator if necessary)
REM do not use EnableDelayedExpansion here, it messes with the != symbols
echo from __future__ import print_function > _parent_package_path.py
echo import os >> _parent_package_path.py
echo env_name = 'CATKIN_WORKSPACES' >> _parent_package_path.py
echo items = os.environ[env_name].split(';') if env_name in os.environ and os.environ[env_name] != '' else [] >> _parent_package_path.py
echo path = '' >> _parent_package_path.py
echo for item in items: >> _parent_package_path.py
echo     path += ':' + (os.path.join(item, 'share') if item.find(':') == -1 else item.split(':')[1]) >> _parent_package_path.py
echo print(path) >> _parent_package_path.py

setlocal EnableDelayedExpansion

set ROS_PACKAGE_PATH_PARENTS=
for /f %%a in ('python _parent_package_path.py') do set ROS_PACKAGE_PATH_PARENTS=!ROS_PACKAGE_PATH_PARENTS!%%a

@[if DEVELSPACE]@
REM env variables in develspace
set ROS_PACKAGE_PATH=@(CMAKE_SOURCE_DIR)$ROS_PACKAGE_PATH_PARENTS
set ROS_ETC_DIR=@(CATKIN_DEVEL_PREFIX)/@(CATKIN_GLOBAL_ETC_DESTINATION)/ros
@[else]@
REM env variables in installspace
set ROS_PACKAGE_PATH=@(CMAKE_INSTALL_PREFIX)/share:@(CMAKE_INSTALL_PREFIX)/stacks$ROS_PACKAGE_PATH_PARENTS
set ROS_ETC_DIR=@(CMAKE_INSTALL_PREFIX)/@(CATKIN_GLOBAL_ETC_DESTINATION)/ros
@[end if]@

del _parent_package_path.py

endlocal

REM unset ROS workspace
set ROS_WORKSPACE=
set COMMAND=


fixed dependency definition for cmake usage

@[if DEVELSPACE]@
set(_xacro_py
  @(CMAKE_CURRENT_SOURCE_DIR)/scripts/xacro
  )
@[else]@
set(_xacro_py
  ${xacro_DIR}/../../../@(CATKIN_PACKAGE_BIN_DESTINATION)/xacro
  )
@[end if]@

add_custom_target(${PROJECT_NAME}_xacro_generated_to_devel_space_ ALL)

## xacro_add_xacro_file(<input> [<output>] [INORDER] [REMAP <arg> <arg> ...]
##                      [OUTPUT <variable>])
##
## Creates a command run xacro on <input> like so:
## xacro [--inorder] -o <output> <input> [<remap args>]
##
## If <output> was not specified, it is determined from <input> removing the suffix .xacro
## The absolute output file name is returned in variable <output>, which defaults to
## XACRO_OUTPUT_FILE.
##
## In order to actually build and install, you need to provide a custom target:
## foreach(xacro_file ${MY_XACRO_FILES})
##   xacro_add_xacro_file(${xacro_file} INORDER REMAP bar:=foo foo:=bar)
##   list(APPEND xacro_outputs ${XACRO_OUTPUT_FILE})
## endforeach()
## xacro_install(xacro_target ${xacro_outputs} DESTINATION xml)
##
## Be aware, that xacro_install() is required to install into both, install and devel space.
## Normal install() only installs into install space!
##
## For conveniency, you might want to use xacro_add_files(), which does the same:
## xacro_add_files(${MY_XACRO_FILES} INORDER REMAP bar:=foo foo:=bar
##                 TARGET xacro_target INSTALL DESTINATION xml)
function(xacro_add_xacro_file input)
  # parse arguments
  set(options INORDER)
  set(oneValueArgs OUTPUT)
  set(multiValueArgs REMAP)
  cmake_parse_arguments(_XACRO "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

  ## process arguments
  # retrieve output file name
  if(_XACRO_UNPARSED_ARGUMENTS)
    # output file explicitly specified
    list(GET _XACRO_UNPARSED_ARGUMENTS 0 output)
    list(REMOVE_AT _XACRO_UNPARSED_ARGUMENTS 0)
    # any remaining unparsed args?
    if(_XACRO_UNPARSED_ARGUMENTS)
      message(WARNING "unknown arguments: ${_XACRO_UNPARSED_ARGUMENTS}")
    endif(_XACRO_UNPARSED_ARGUMENTS)
  else()
    # implicitly determine output file from input
    if(${input} MATCHES "(.*)[.]xacro$")
      set(output ${CMAKE_MATCH_1})
    else()
      message(FATAL_ERROR "no <output> specified for: " ${input})
    endif()
  endif()
  # message(STATUS "output: ${output}")

  # transform _XACRO_INORDER's BOOL value
  if(_XACRO_INORDER)
    set(_XACRO_INORDER "--inorder")
  else()
    unset(_XACRO_INORDER)
  endif()

  ## determine absolute output target location
  if(IS_ABSOLUTE ${output})
    set(abs_output ${output})
  else()
    set(abs_output ${CMAKE_CURRENT_BINARY_DIR}/${output})
  endif()
  # message(STATUS "abs_output: ${abs_output}")

  ## export abs_output to parent scope in variable ${_XACRO_OUTPUT}
  if(NOT _XACRO_OUTPUT)
    set(_XACRO_OUTPUT XACRO_OUTPUT_FILE)
  endif()
  set(${_XACRO_OUTPUT} ${abs_output} PARENT_SCOPE)

  ## Call out to xacro to determine dependencies
  message(STATUS "xacro: determining deps for: " ${input} " ...")
  execute_process(COMMAND ${_xacro_py} ${_XACRO_INORDER} --deps ${input} ${_XACRO_REMAP}
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    ERROR_VARIABLE _xacro_err
    OUTPUT_VARIABLE _xacro_deps_result
    OUTPUT_STRIP_TRAILING_WHITESPACE)
  if(_xacro_err)
    message(WARNING "failed to determine deps for: ${input}
${_xacro_err}")
  endif(_xacro_err)

  separate_arguments(_xacro_deps_result)

  ## command to actually call xacro
  add_custom_command(OUTPUT ${output}
    COMMAND ${CATKIN_ENV} ${_xacro_py} ${_XACRO_INORDER} -o ${abs_output} ${input} ${_XACRO_REMAP}
    DEPENDS ${input} ${_xacro_deps_result}
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    COMMENT "xacro: generating ${output} from ${input}"
    )
endfunction(xacro_add_xacro_file)

## xacro_install(<target> <output> [<output> ...] DESTINATION <path>)
##
## installs xacro-generated files both to devel and input space
## into ${CATKIN_PACKAGE_SHARE_DESTINATION}/<path>
function(xacro_install target)
  # parse arguments
  set(oneValueArgs DESTINATION)
  cmake_parse_arguments(_XACRO "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  set(outputs ${_XACRO_UNPARSED_ARGUMENTS})

  ## rule to create target dir
  file(TO_CMAKE_PATH ${CATKIN_PACKAGE_SHARE_DESTINATION}/${_XACRO_DESTINATION} dest)
  file(TO_CMAKE_PATH ${CATKIN_DEVEL_PREFIX}/${dest} TARGET_DIR)
  add_custom_command(OUTPUT ${TARGET_DIR}
    COMMAND ${CMAKE_COMMAND} -E make_directory ${TARGET_DIR}
    COMMENT "creating dir ${TARGET_DIR}")

  ## process list of outputs
  foreach(output ${outputs})
    get_filename_component(tgt ${output} NAME)
    file(TO_CMAKE_PATH ${TARGET_DIR}/${tgt} tgt)
    list(APPEND tgts ${tgt})

    # rule to create devel space tgt
    add_custom_command(OUTPUT ${tgt}
      COMMAND ${CMAKE_COMMAND} -E copy_if_different ${output} ${tgt}
      DEPENDS ${TARGET_DIR} ${output}
      COMMENT "Copying to devel space: ${tgt}"
      )
  endforeach()

  ## rule to create devel space tgts
  add_custom_target(${PROJECT_NAME}_${target}_to_devel_space_ DEPENDS ${tgts})
  # add to main target _xacro_generated_to_devel_space_
  add_dependencies(${PROJECT_NAME}_xacro_generated_to_devel_space_
                   ${PROJECT_NAME}_${target}_to_devel_space_)

  ## normal install
  install(FILES ${outputs} DESTINATION ${dest})
endfunction(xacro_install)

## xacro_add_files(<file> [<file> ...] [INORDER] [REMAP <arg> <arg> ...]
##                 [TARGET <target>] [INSTALL [DESTINATION <path>]])
##
## create make <target> to generate xacro files
## and optionally install to ${CATKIN_PACKAGE_SHARE_DESTINATION}/<path>
## in devel and install space.
function(xacro_add_files)
  # parse arguments
  set(options INORDER INSTALL)
  set(oneValueArgs OUTPUT TARGET DESTINATION)
  set(multiValueArgs REMAP)
  cmake_parse_arguments(_XACRO "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

  ## process arguments
  # transform _XACRO_INORDER's BOOL value
  if(_XACRO_INORDER)
    set(_XACRO_INORDER "INORDER")
  else()
    unset(_XACRO_INORDER)
  endif()

  # prepare REMAP args (prepending REMAP)
  if(_XACRO_REMAP)
    set(_XACRO_REMAP REMAP ${_XACRO_REMAP})
  endif()

  # have INSTALL option, but no TARGET: fallback to default target
  if(_XACRO_INSTALL AND NOT _XACRO_TARGET)
    # message(STATUS "xacro: no TARGET specified, using default")
    set(_XACRO_TARGET _xacro_auto_generate)
  endif()

  foreach(input ${_XACRO_UNPARSED_ARGUMENTS})
    # call to main function
    xacro_add_xacro_file(${input} ${_XACRO_OUTPUT} ${_XACRO_INORDER} ${_XACRO_REMAP})
    list(APPEND outputs ${XACRO_OUTPUT_FILE})
  endforeach()

  if(outputs)
    # link to target
    add_custom_target(${PROJECT_NAME}_${_XACRO_TARGET} ALL DEPENDS ${outputs})

    # install?
    if(_XACRO_INSTALL)
      xacro_install(${_XACRO_TARGET} ${outputs} DESTINATION ${_XACRO_DESTINATION})
    endif(_XACRO_INSTALL)
  endif()
endfunction(xacro_add_files)

@[if DEVELSPACE]@
set(_xacro_py
  @(CMAKE_CURRENT_SOURCE_DIR)/scripts/xacro
  )
@[else]@
set(_xacro_py
  ${xacro_DIR}/../../../@(CATKIN_PACKAGE_BIN_DESTINATION)/xacro
  )
@[end if]@

add_custom_target(${PROJECT_NAME}_xacro_generated_to_devel_space_ ALL)

## xacro_add_xacro_file(<input> [<output>] [INORDER] [REMAP <arg> <arg> ...]
##                      [OUTPUT <variable>])
##
## Creates a command run xacro on <input> like so:
## xacro [--inorder] -o <output> <input> [<remap args>]
##
## If <output> was not specified, it is determined from <input> removing the suffix .xacro
## The absolute output file name is returned in variable <output>, which defaults to
## XACRO_OUTPUT_FILE.
##
## In order to actually build and install, you need to provide a custom target:
## foreach(xacro_file ${MY_XACRO_FILES})
##   xacro_add_xacro_file(${xacro_file} INORDER REMAP bar:=foo foo:=bar)
##   list(APPEND xacro_outputs ${XACRO_OUTPUT_FILE})
## endforeach()
## xacro_install(xacro_target ${xacro_outputs} DESTINATION xml)
##
## Be aware, that xacro_install() is required to install into both, install and devel space.
## Normal install() only installs into install space!
##
## For conveniency, you might want to use xacro_add_files(), which does the same:
## xacro_add_files(${MY_XACRO_FILES} INORDER REMAP bar:=foo foo:=bar
##                 TARGET xacro_target INSTALL DESTINATION xml)
function(xacro_add_xacro_file input)
  # parse arguments
  set(options INORDER)
  set(oneValueArgs OUTPUT)
  set(multiValueArgs REMAP)
  cmake_parse_arguments(_XACRO "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

  ## process arguments
  # retrieve output file name
  if(_XACRO_UNPARSED_ARGUMENTS)
    # output file explicitly specified
    list(GET _XACRO_UNPARSED_ARGUMENTS 0 output)
    list(REMOVE_AT _XACRO_UNPARSED_ARGUMENTS 0)
    # any remaining unparsed args?
    if(_XACRO_UNPARSED_ARGUMENTS)
      message(WARNING "unknown arguments: ${_XACRO_UNPARSED_ARGUMENTS}")
    endif(_XACRO_UNPARSED_ARGUMENTS)
  else()
    # implicitly determine output file from input
    if(${input} MATCHES "(.*)[.]xacro$")
      set(output ${CMAKE_MATCH_1})
    else()
      message(FATAL_ERROR "no <output> specified for: " ${input})
    endif()
  endif()
  # message(STATUS "output: ${output}")

  # transform _XACRO_INORDER's BOOL value
  if(_XACRO_INORDER)
    set(_XACRO_INORDER "--inorder")
  else()
    unset(_XACRO_INORDER)
  endif()

  ## determine absolute output target location
  if(IS_ABSOLUTE ${output})
    set(abs_output ${output})
  else()
    set(abs_output ${CMAKE_CURRENT_BINARY_DIR}/${output})
  endif()
  # message(STATUS "abs_output: ${abs_output}")

  ## export abs_output to parent scope in variable ${_XACRO_OUTPUT}
  if(NOT _XACRO_OUTPUT)
    set(_XACRO_OUTPUT XACRO_OUTPUT_FILE)
  endif()
  set(${_XACRO_OUTPUT} ${abs_output} PARENT_SCOPE)

  ## Call out to xacro to determine dependencies
  message(STATUS "xacro: determining deps for: " ${input} " ...")
  execute_process(COMMAND ${_xacro_py} --deps ${input} ${_XACRO_REMAP}
    WORKING_DIRECTORY $(CMAKE_CURRENT_SOURCE_DIR)
    ERROR_VARIABLE _xacro_err
    OUTPUT_VARIABLE _xacro_deps_result
    OUTPUT_STRIP_TRAILING_WHITESPACE)
  if(_xacro_err)
    message(WARNING "failed to determine deps for: ${input}
${_xacro_err}")
  endif(_xacro_err)

  separate_arguments(_xacro_deps_result)

  ## command to actually call xacro
  add_custom_command(OUTPUT ${output}
    COMMAND ${CATKIN_ENV} ${_xacro_py} ${_XACRO_INORDER} -o ${abs_output} ${input} ${_XACRO_REMAP}
    DEPENDS ${input} ${_xacro_deps_result}
    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
    COMMENT "xacro: generating ${output} from ${input}"
    )
endfunction(xacro_add_xacro_file)

## xacro_install(<target> <output> [<output> ...] DESTINATION <path>)
##
## installs xacro-generated files both to devel and input space
## into ${CATKIN_PACKAGE_SHARE_DESTINATION}/<path>
function(xacro_install target)
  # parse arguments
  set(oneValueArgs DESTINATION)
  cmake_parse_arguments(_XACRO "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  set(outputs ${_XACRO_UNPARSED_ARGUMENTS})

  ## rule to create target dir
  file(TO_CMAKE_PATH ${CATKIN_PACKAGE_SHARE_DESTINATION}/${_XACRO_DESTINATION} dest)
  file(TO_CMAKE_PATH ${CATKIN_DEVEL_PREFIX}/${dest} TARGET_DIR)
  add_custom_command(OUTPUT ${TARGET_DIR}
    COMMAND ${CMAKE_COMMAND} -E make_directory ${TARGET_DIR}
    COMMENT "creating dir ${TARGET_DIR}")

  ## process list of outputs
  foreach(output ${outputs})
    get_filename_component(tgt ${output} NAME)
    file(TO_CMAKE_PATH ${TARGET_DIR}/${tgt} tgt)
    list(APPEND tgts ${tgt})

    # rule to create devel space tgt
    add_custom_command(OUTPUT ${tgt}
      COMMAND ${CMAKE_COMMAND} -E copy_if_different ${output} ${tgt}
      DEPENDS ${TARGET_DIR} ${output}
      COMMENT "Copying to devel space: ${tgt}"
      )
  endforeach()

  ## rule to create devel space tgts
  add_custom_target(${PROJECT_NAME}_${target}_to_devel_space_ DEPENDS ${tgts})
  # add to main target _xacro_generated_to_devel_space_
  add_dependencies(${PROJECT_NAME}_xacro_generated_to_devel_space_
                   ${PROJECT_NAME}_${target}_to_devel_space_)

  ## normal install
  install(FILES ${outputs} DESTINATION ${dest})
endfunction(xacro_install)

## xacro_add_files(<file> [<file> ...] [INORDER] [REMAP <arg> <arg> ...]
##                 [TARGET <target>] [INSTALL [DESTINATION <path>]])
##
## create make <target> to generate xacro files
## and optionally install to ${CATKIN_PACKAGE_SHARE_DESTINATION}/<path>
## in devel and install space.
function(xacro_add_files)
  # parse arguments
  set(options INORDER INSTALL)
  set(oneValueArgs OUTPUT TARGET DESTINATION)
  set(multiValueArgs REMAP)
  cmake_parse_arguments(_XACRO "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

  ## process arguments
  # transform _XACRO_INORDER's BOOL value
  if(_XACRO_INORDER)
    set(_XACRO_INORDER "INORDER")
  else()
    unset(_XACRO_INORDER)
  endif()

  # prepare REMAP args (prepending REMAP)
  if(_XACRO_REMAP)
    set(_XACRO_REMAP REMAP ${_XACRO_REMAP})
  endif()

  # have INSTALL option, but no TARGET: fallback to default target
  if(_XACRO_INSTALL AND NOT _XACRO_TARGET)
    # message(STATUS "xacro: no TARGET specified, using default")
    set(_XACRO_TARGET _xacro_auto_generate)
  endif()

  foreach(input ${_XACRO_UNPARSED_ARGUMENTS})
    # call to main function
    xacro_add_xacro_file(${input} ${_XACRO_OUTPUT} ${_XACRO_INORDER} ${_XACRO_REMAP})
    list(APPEND outputs ${XACRO_OUTPUT_FILE})
  endforeach()

  if(outputs)
    # link to target
    add_custom_target(${PROJECT_NAME}_${_XACRO_TARGET} ALL DEPENDS ${outputs})

    # install?
    if(_XACRO_INSTALL)
      xacro_install(${_XACRO_TARGET} ${outputs} DESTINATION ${_XACRO_DESTINATION})
    endif(_XACRO_INSTALL)
  endif()
endfunction(xacro_add_files)