@Override
	@SuppressWarnings("unchecked")
	public DVector getQuestTemplate(MOB mob, String fileToGet)
	{
		// user security doesn't matter, because this is read-only & system files.
		final int fileOpenFlag=CMFile.FLAG_LOGERRORS|(CMSecurity.isAllowedAnywhere(mob, CMSecurity.SecFlag.CMDQUESTS)?CMFile.FLAG_FORCEALLOW:0);
		final CMFile tempF=new CMFile(Resources.makeFileResourceName("quests/templates"),null,fileOpenFlag);
		if((!tempF.exists())||(!tempF.isDirectory()))
			return null;
		final CMFile[] files=tempF.listFiles();
		final DVector templatesDV=new DVector(5);
		final boolean parsePages=(fileToGet!=null)&&(!fileToGet.endsWith("*"));
		if((fileToGet!=null)&&(fileToGet.endsWith("*")))
			fileToGet=fileToGet.substring(0,fileToGet.length()-1);
		if(files.length==0)
			return null;
		for (final CMFile file : files)
		{
			if((file.getName().toUpperCase().endsWith(".QUEST"))
			&&((fileToGet==null)||(file.getName().toUpperCase().startsWith(fileToGet.toUpperCase().trim()))))
			{
				final List<String> V=Resources.getFileLineVector(file.text());
				String s=null;
				boolean foundStart=false;
				boolean foundQuestScript=false;
				DVector pageDV=null;
				StringBuffer script=null;
				for(int v=0;v<V.size();v++)
				{
					s=V.get(v).trim();
					if((foundQuestScript)&&(script!=null))
						script.append(s+"\n\r");
					else
					if(s.startsWith("#"))
					{
						s=s.substring(1).trim();
						if(s.startsWith("!"))
						{
							s=s.substring(1).trim();
							if(s.startsWith("QUESTMAKER_START_SCRIPT"))
							{
								final String name=s.substring(23).trim();
								foundStart=true;
								script=new StringBuffer("");
								templatesDV.addElement(name,"",file.getName(),new Vector<Object>(),script);
							}
							else
							if(s.startsWith("QUESTMAKER_END_SCRIPT")&&(foundStart))
							{
								foundStart=false;
								foundQuestScript=true;
								continue;
							}
							else
							if(s.startsWith("QUESTMAKER_PAGE")&&(foundStart))
							{
								if(!parsePages)
									break;
								final String name=s.substring(15).trim();
								pageDV=new DVector(4);
								pageDV.addElement(Integer.valueOf(QuestManager.QMCommand.$TITLE.ordinal()),name,"","");
								((Vector<Object>)templatesDV.elementAt(templatesDV.size()-1,4)).addElement(pageDV);
							}
							else
							if(s.trim().length()>0)
								Log.errOut("Quests","Unrecognized meta-questmaker command: "+s);
						}
						else
						if(s.startsWith("$")&&(foundStart))
						{
							if(parsePages)
							{
								final int x=s.indexOf('=');
								if(x<0)
									Log.errOut("Quests","Illegal QuestMaker variable syntax: "+s);
								else
								if(pageDV==null)
									Log.errOut("Quests","QuestMaker syntax error, QUESTMAKER_PAGE not yet designated: "+s);
								else
								{
									final int y=s.indexOf('=',x+1);
									if(y>=0)
										pageDV.addElement(s.substring(x+1,y).trim(),s.substring(0,x),s.substring(y+1),"");
									else
										pageDV.addElement(s.substring(x+1).trim(),s.substring(0,x),"","");
									String cmd=(String)pageDV.elementAt(pageDV.size()-1,1);
									int mask=0;
									if(cmd.startsWith("(")&&cmd.endsWith(")"))
									{
										mask=mask|QuestManager.QM_COMMAND_OPTIONAL;
										cmd=cmd.substring(1,cmd.length()-1);
									}
									final QMCommand command = (QMCommand)CMath.s_valueOf(QMCommand.class, cmd);
									if(command == null)
									{
										Log.errOut("Quests","QuestMaker syntax error, '"+cmd+"' is an unknown command");
										pageDV.removeElementsAt(pageDV.size()-1);
									}
									else
										pageDV.setElementAt(pageDV.size()-1,1,Integer.valueOf(command.ordinal()|mask));
								}
							}
						}
						else
						if(foundStart)
						{
							if(pageDV==null)
							{
								if(s.length()==0)
									templatesDV.setElementAt(templatesDV.size()-1,2,((String)templatesDV.elementAt(templatesDV.size()-1,2))+"\n\r\n\r");
								else
									templatesDV.setElementAt(templatesDV.size()-1,2,((String)templatesDV.elementAt(templatesDV.size()-1,2))+s+" ");
							}
							else
							if(parsePages)
							{
								if((pageDV.size()<2)
								||(((Integer)pageDV.elementAt(pageDV.size()-1,1)).intValue()==QuestManager.QMCommand.$TITLE.ordinal())
								||(((Integer)pageDV.elementAt(pageDV.size()-1,1)).intValue()==QuestManager.QMCommand.$LABEL.ordinal()))
								{
									if(s.length()==0)
									{
										if(((Integer)pageDV.elementAt(pageDV.size()-1,1)).intValue()==QuestManager.QMCommand.$TITLE.ordinal())
											pageDV.addElement(Integer.valueOf(QuestManager.QMCommand.$LABEL.ordinal()),"",s,"");
										else
											pageDV.setElementAt(pageDV.size()-1,3,((String)pageDV.elementAt(pageDV.size()-1,3))+"\n\r\n\r");
									}
									else
										pageDV.setElementAt(pageDV.size()-1,3,((String)pageDV.elementAt(pageDV.size()-1,3))+s+" ");
								}
								else
									pageDV.addElement(Integer.valueOf(QuestManager.QMCommand.$LABEL.ordinal()),"",s,"");
							}
						}
					}
				}

			}
		}
		if(templatesDV.size()==0)
			return null;
		final DVector sortedTemplatesDV=new DVector(5);
		while(templatesDV.size()>0)
		{
			int maxRow=0;
			for(int t=1;t<templatesDV.size();t++)
			{
				if(((String)templatesDV.elementAt(t,1)).compareTo((String)templatesDV.elementAt(maxRow,1))<0)
					maxRow=t;
			}
			sortedTemplatesDV.addElement(templatesDV.elementAt(maxRow,1),
										 templatesDV.elementAt(maxRow,2),
										 templatesDV.elementAt(maxRow,3),
										 templatesDV.elementAt(maxRow,4),
										 templatesDV.elementAt(maxRow,5));
			templatesDV.removeElementsAt(maxRow);
		}
		return sortedTemplatesDV;
	}