import java.util.*; import java.io.*; import java.util.regex.*; import java.net.*; import java.math.*; public class main { static boolean debug = true; static String[] standardFunctions = { "#1002425/runTranslatorQuick", "#1002423/tag", "#1002421/highest", "#1002419/newParser", "#1002416/isDigit", "#1002415/structureLines", "#1002411/rand", "#1002407/getTuringScore", "#1002406/run_overBot", "#1002403/lastTiming", "#1002401/getDispatcher", "#1002400/evalWith", "#1002399/jparse", "#1002397/unidiff", "#1002395/eval", "#1002393/logStructure", "#1002392/makeEleuSet", "#1002389/selfLink", "#1002388/hiddenFields", "#1002377/a", "#1002376/askSelf", "#1002374/loadSnippetThroughBot", "#1002359/getSlackTS", "#1002354/unixDay", "#1002348/nempty", "#1002346/secretProgramFile", "#1002345/serveHttps", "#1002334/editSnippet", "#1002336/createSnippet", "#1002335/eleuSnippetPassword", "#1002333/hquery", "#1002322/compileBot_clearCache", "#1002320/getMemoryInfo", "#1002319/filterByField", "#1002318/collectField", "#1002316/findByField", "#1002315/synchroHashSet", "#1002309/findContainerTag", "#1002305/removeLast", "#1002303/reverseLookup", "#1002300/setAdd", "#1002292/mergeBracketThingies", "#1002291/unbracket", "#1002290/isBracketedID", "#1002288/printStackTrace", "#1002287/lithashset", "#1002285/assertIdentifier", "#1002284/splitAtJavaToken", "#1002283/printF", "#1002276/callOtherBot", "#1002275/getBot", "#1002274/getFromOtherBot", "#1002273/getActualURI", "#1002271/splitByJavaToken", "#1002270/getMainBot", "#1002269/getUserName", "#1002266/getLastTiming", "#1002263/saveTiming", "#1002248/getCacheProgramDir", "#1002246/hotwire_overBot", "#1002244/touchFile", "#1002226/logOutput", "#1002224/hotwireCached", "#1002218/lastN", "#1002214/htag", "#1002209/getClassName", "#1002208/asRuntimeException", "#1002207/softFail", "#1002206/assertIsIdentifier", "#1002204/dir2zip_recurse", "#1002202/getNameOfPublicClass", "#1002201/hasModifier", "#1002200/getJavaModifiers", "#1002199/exceptionToUser", "#1002198/throwableToUser", "#1002197/formatExceptionForUser", "#1002196/formatChannelName", "#1002195/getHashSet", "#1002194/countDistinct", "#1002193/devChannelToken", "#1002189/restructure", "#1002188/mapBasedReplace", "#1002186/tokRegionMatchIC", "#1002183/multiSlurp", "#1002180/hasMethodNamed", "#1002179/objectToMap", "#1002178/copyFields", "#1002177/getAverage", "#1002176/round", "#1002175/toDouble", "#1002172/loadRelpToken", "#1002170/slackGetChannelIDs", "#1002169/slackSlurp", "#1002162/isLinux", "#1002151/unixHour", "#1002149/removeIgnoreCase", "#1002148/containsIgnoreCase", "#1002147/splitListBy", "#1002146/printFormat", "#1002145/randomOne", "#1002144/unq", "#1002141/htmlQuery", "#1002137/snippetImageURL", "#1002136/replaceSublist", "#1002135/indexOfSubList", "#1002133/jreplace", "#1002127/quoteAll", "#1002126/scanToEndOfInitializer", "#1002125/findInitializers", "#1002118/getBracketMap", "#1002116/liftLast", "#1002113/getPlural", "#1002112/n", "#1002111/getSortedSet", "#1002110/dropPrefix", "#1002109/isNonNegativeInteger", "#1002108/empty", "#1002107/lookupPossiblyIgnoreCase", "#1002106/endsWithOneOf", "#1002104/loadTextFileFromZip", "#1002103/listZip", "#1002102/loadBinary", "#1002099/cppCopy", "#1002098/resizeCollection", "#1002097/replaceCollection", "#1002092/list", "#1002091/nullIfEmpty", "#1002090/loadSnippetVersion", "#1002088/listFilesWithSuffix", "#1002086/endsWithIgnoreCase", "#1002085/deleteAllFilesWithSuffix", "#1002082/isLowerHexString", "#1002081/isMD5", "#1002080/getSnippetMD5", "#1002075/rat", "#1002074/filterByMethod", "#1002073/joinQuoted", "#1002071/trim", "#1002066/licensed", "#1002062/unixTime", "#1002058/emptyToNull", "#1002055/replaceToken", "#1002051/stdEq", "#1002050/allToString", "#1002048/dropSuffix", "#1002047/bigint", "#1002042/keys", "#1002041/cmp", "#1002040/keyWithBiggestValue", "#1002038/dataSize", "#1002037/printMemoryInfo", "#1002035/toM_double", "#1002034/gcAndPrintMemoryInfo", "#1002033/random", "#1002032/fromUTF8", "#1002031/loadTextFileFromZipFile", "#1002029/listZipFile", "#1002026/toLower", "#1002025/load", "#1002024/save", "#1002022/isEmpty", "#1002021/booleanValue", "#1002019/allMethodNames", "#1002014/mainClass", "#1002013/toObjectArray", "#1002012/assertNotNull", "#1002010/totalLengthOfCodeTokens", "#1001998/pythonToJavaTok", "#1001996/loadVariableDefinition", "#1001995/lookupIgnoreCase", "#1001992/str", "#1001990/allInjectionsPrettyList", "#1001988/padList", "#1001986/htmlTable", "#1001985/instanceOf", "#1001984/dataToTable_makeRow", "#1001978/slackGetUserName", "#1001975/simpleSpaces", "#1001974/smartSet", "#1001970/loadLog", "#1001967/assertFalse", "#1001965/sendToLocalBot_cached", "#1001964/newFindBot", "#1001963/matchMetaNoStar", "#1001960/synchroTreeMap", "#1001959/callHtmlMethod", "#1001954/getString", "#1001952/toM", "#1001949/getProgramFile", "#1001948/scanLog", "#1001946/mathOp", "#1001944/matchMeta", "#1001941/getNumberOfComputers", "#1001940/slackReactionScore", "#1001939/printStructure", "#1001936/slackReact", "#1001935/slackSmile", "#1001933/makePostData", "#1001931/cleanUp", "#1001930/feedbackScore", "#1001929/collapseWord", "#1001927/diff", "#1001926/slackReadChannel", "#1001924/count", "#1001922/numberLines", "#1001921/replaceWords", "#1001918/jsonDecodeMap", "#1001917/slackGetUserInfo", "#1001914/emptyList", "#1002310/subList", "#1001909/printList", "#1001907/slackReadTalkingBots", "#1001906/reversedList", "#1001902/loadTextFileMandatory", "#1001901/loadSecretTextFileMandatory", "#1001900/loadSecretTextFile", "#1001899/asSet", "#1001898/dropWords", "#1001896/toLowerCase", "#1001895/hasTransitive", "#1001894/makeHull", "#1001892/isIdentifier", "#1001891/format", "#1001885/replaceKeywordBlock", "#1001880/fill", "#1001879/statements", "#1001878/indexOf", "#1001876/jmatch", "#1001875/mousePosition", "#1001871/group", "#1001870/newObject", "#1001866/tagGet", "#1001865/neq", "#1001863/findTopLevelClass", "#1001860/htmlEncode", "#1001858/getAuthorOfSignedJava", "#1001856/signJavaWithComputerID", "#1001855/htmlQuote", "#1001854/containsSnippetID", "#1001853/substr", "#1001852/serve404", "#1001851/isString", "#1001850/sortFilesByName", "#1001843/string", "#1001842/match", "#1001840/assertEq", "#1001838/make", "#1001832/magicIndexOfSubList", "#1001828/defaultTranslate", "#1001827/containsToken", "#1001825/onFocusLeave", "#1001823/rightAlign", "#1001822/isChecked", "#1001821/extractMainComponent", "#1001820/run", "#1001818/includeInMain", "#1001817/includesToken", "#1001815/tokMainJava", "#1001809/findBlock", "#1001808/runTranslator", "#1001801/askMyself", "#1001800/callStaticAnswerMethod", "#1001799/safeGet", "#1001798/getLine", "#1001797/dropFirstLine", "#1001796/min", "#1001795/arraycopy", "#1001793/matchStart", "#1001792/makeBot", "#1001790/showBigText", "#1001788/onEnter", "#1001786/htmlBot", "#1001783/hgrid", "#1001781/sendToBotQuietly", "#1001779/runInAllVMs", "#1001780/getOutputOfInjections", "#1001777/allSwingComponents", "#1001774/vgrid", "#1001773/smartAdd", "#1001771/fullBotScan", "#1001767/getBotAddress", "#1001765/defineBot", "#1001763/search", "#1001762/getBotNameFromSnippet", "#1001761/stack", "#1001757/isMap", "#1001755/getSelectedLineAsMap", "#1001754/getSelectedLine", "#1001753/getFocusOwner", "#1001751/containsBot", "#1001750/startBotSeparateVM", "#1001748/startBotVM", "#1001746/updateLoop", "#1001742/getInjectionID", "#1001741/or", "#1001740/talkToAllOtherVMs", "#1001739/getVMPort", "#1001737/makeSilentAndroid", "#1001736/addToMultiPortSilent", "#1001733/setFrameTitle", "#1001730/currentThread", "#1001727/directorySize", "#1001726/numFiles", "#1001725/findAllFiles", "#1001723/allDataDirectories", "#1001721/safeUnstructure", "#1001719/injectToBotVM", "#1001717/newTypeWriterTextArea", "#1001715/shallowClone", "#1001713/hasBot", "#1001712/javaxBot", "#1001711/injectTo", "#1001707/getSelectedColumn", "#1001701/makeResponder", "#1001696/parseDouble", "#1001695/litmap", "#1001693/removeToken", "#1001686/equalsIgnoreCase", "#1001681/sendTestResult", "#1001678/talkToSubBot", "#1001677/startMultiPort", "#1001676/addToMultiPort", "#1001674/getMultiPorts", "#1001673/getVMID", "#1001670/getFileSize", "#1001666/toK", "#1001664/max", "#1001663/rsubstring", "#1001660/convertToDefaultListModel", "#1001659/allSwingComponentsOfType", "#1001658/sendToCentralBotWithTimeout", "#1001657/loadPageWithTimeout", "#1001656/centralServerUp", "#1001654/sendToCentralBot", "#1001653/remoteBotsUp", "#1001650/serveHTML", "#1001648/serveHttp", "#1001645/addToConsole", "#1001644/createJavaProgram", "#1001643/findSnippet", "#1001642/findTranslators", "#1001641/hasCodeTokens", "#1001629/weakref", "#1001637/findAll", "#1001636/scanForComponents", "#1001635/allFrames", "#1001634/cloneList", "#1001633/waitUntilInjectionsDone", "#1001632/injectToAll", "#1001631/createTempProgram", "#1001627/makeList", "#1001626/showSideBySide", "#1001625/wrap", "#1001624/swingUpdate", "#1001623/showFrame", "#1001621/getClassBody", "#1001619/innerClasses", "#1001617/showTable", "#1001613/dataToTable", "#1001606/include", "#1001598/assertTrue", "#1001593/tunnelToRemoteBot", "#1001586/renameVM", "#1001584/unsign", "#1001583/isSignedWithKey", "#1001580/nlTok", "#1001577/suckHumans", "#1001576/suckWebChat", "#1001574/iterateOverBlockingQueue", "#1001573/uploadProgramOutput", "#1001571/getProgramOutput", "#1001568/getPublicKeyOfComputer", "#1001567/getAuthorOfSignedText", "#1001566/signWithComputerID", "#1001565/getMySignatureForText", "#1001564/getMyPublicKey", "#1001563/isRandomID", "#1001562/isComputerID", "#1001560/fullTrim", "#1001557/fromUtf8", "#1001555/getTimeToHEAD", "#1001553/dropPrefixMandatory", "#1001552/base64decode", "#1001549/getSecretProgramDir", "#1001544/sayInWebChat", "#1001543/ltrim", "#1001540/stdcompare", "#1001539/sortByIndex", "#1001538/sortByFirstColumn", "#1001537/setTableModel", "#1001536/firstPartOfHelloString", "#1001530/structureOrText", "#1001529/addSaveButton", "#1001528/addToWindow", "#1001527/addCommentToWindow", "#1001523/showColoredText", "#1001520/eqic", "#1001504/makeExecutable", "#1001499/startsWithIgnoreCase", "#1001498/isType", "#1001497/parseBoolean", "#1001491/getOS", "#1001488/tokenLineNr", "#1001484/autoFrameTitle", "#1001483/sendToAllVMs", "#1001481/programsRunningInAllVMs", "#1001480/programsRunningInVM", "#1001479/canHyperMove", "#1001478/fastNohupJavax", "#1001477/runInNewThread", "#1001473/isVMRunningProgram", "#1001470/programIsRunning", "#1001466/hyperMoveAnother", "#1001463/isMac", "#1001462/userDir", "#1001461/listDirs", "#1001459/listFiles", "#1001458/showList", "#1001456/logQuoted", "#1001454/tempDir", "#1001450/moveDown", "#1001445/toGrayScale", "#1001439/getFrameTitle", "#1001438/fillTableWithStrings", "#1001436/talkToAllVMs", "#1001433/getScreenSize", "#1001432/moveToTopRightCorner", "#1001431/fillListWithStrings", "#1001429/getNumberOfJavaXVMs", "#1001428/getFrame", "#1001422/getBotPort", "#1001419/verifyMD5", "#1001518/l", "#1001516/len", "#1001418/length", "#1001411/isURL", "#1001407/getInstance", "#1001400/sendToAll", "#1001399/talkToAll", "#1001396/saveProgramTextFile", "#1001395/getSupportedQuestions", "#1001393/getSnippetFromBossBot", "#1001394/boss", "#1001381/startPreSpunVM", "#1001380/countPreSpunVMs", "#1001378/countBotsNamed", "#1001375/injectable", "#1001373/listAllFrames", "#1001372/nohupJavax", "#1001368/hyperMove", "#1001366/waitForBotStartUp", "#1001365/startBot", "#1001352/restartProgramID", "#1001347/shootScreen", "#1001346/showImage", "#1001340/zipBot", "#1001338/backupAndCleanProgramDir", "#1001336/stream2file", "#1001335/zip2dir", "#1001333/sameSnippetID", "#1001332/killPortAndWait", "#1001331/killProgramID", "#1001330/getListOfRunningProgramIDs", "#1001329/sendToLocalBot", "#1001326/programID", "#1001323/parseBool", "#1001322/sendToLocalBotOpt", "#1001320/myVMPort", "#1001315/grep", "#1001314/processIDExists", "#1001313/swingLater", "#1001308/centerFrame", "#1001301/androidSayInGerman", "#1001299/standardQuery", "#1001299/additionalQuery", "#1001295/oneOf", "#1001292/androidLater", "#1001291/androidShowFullScreenColor", "#1001282/androidShow", "#1001281/androidShowFullScreenImage", "#1001277/androidUnmuteAudio", "#1001275/androidMuteAudio", "#1001273/makeSpeechCereproc", "#1001271/androidPlayMp3", "#1001267/playMp3", "#1001266/getProgramDir", "#1001263/htmlencode", "#1001262/isTag", "#1001261/gunzipBinaryData", "#1001256/makeAndroid3", "#1001255/findStaticMethod", "#1001251/sendToRemoteBot", "#1001250/format3", "#1001246/parseLong", "#1001243/joinRest", "#1001241/concatLists", "#1001239/quote", "#1001238/getSnippetMD5", "#1001235/toStringArray", "#1001234/find2", "#1001232/find3", "#1001226/contactMyself", "#1001219/getAutoReportToChat", "#1001217/findMandatoryBot", "#1001208/makeTempDir", "#1001204/findMainClass", "#1001303/findBot", "#1001199/callOpt", "#1001198/sentenceEq", "#1001194/quoteIfNotIdentifier", "#1001193/findCodeTokens", "#1001190/synchroTreeSet", "#1001189/readLineHidden", "#1001185/getChatHistory", "#1001184/getMyComputerID", "#1001183/getComputerID", "#1001181/getMyIPs", "#1001180/pcall", "#1001179/detectGateways", "#1001174/dir2zip", "#1001173/zip2zip", "#1001172/renameToken", "#1001166/toUtf8", "#1001165/findEndOfBracketPart", "#1001162/getClassDeclarationName", "#1001161/getVarDeclarationName", "#1001160/findEndOfTypeArgs", "#1001159/allVariableDeclarations", "#1001158/clearAllTokens", "#1001157/allClasses", "#1001156/leftScanModifiers", "#1001154/getServerTranspiled", "#1001152/getMainClass", "#1001151/getInnerException", "#1001147/telnetFromConsoleTo", "#1001144/latestInstalledJavaX", "#1001142/showText_fontSize", "#1001141/firstToUpper", "#1001139/quickBotScan", "#1001138/isJavaIdentifier", "#1001137/findClass", "#1001136/nuObject", "#1001135/isQuoted", "#1001127/publicCommOn", "#1001124/record", "#1001123/listFields", "#1001122/getPID", "#1001116/sleepSeconds", "#1001114/checkIfHttpServerIsOnline", "#1001112/getProgramID", "#1001111/codeTokensOnly", "#1001106/showText", "#1001066/startDialogServerOnPortAbove", "#1001233/parse3", "#1001104/match3", "#1001103/makeAndroid", "#1001103/makeAndroid2", "#1001103/makeAndroidNoConsole", "#1001101/getOpt", "#1001087/answerQuestionsOnPort", "#1001087/answerQuestionsOnPortAndConsole", "#1001084/reverseString", "#1001076/talkTo", "#1001074/readLine", "#1001070/sendKillSwitch", "#1001068/synchroList", "#1001067/appendToFile", "#1001066/startDialogServerIfPortAvailable", "#1001066/startDialogServer", "#1001355/unstructure", "#1001058/deleteDirectory", "#1001056/interpret", "#1001055/assertEquals", "#1001052/programDir", "#1001051/listProgramDir", "#1001044/saveLocally", "#1001043/readLocally", "#1001047/litlist", "#1001046/findEndOfBlock", "#1001039/quickProgramScan", "#1001038/last", "#1001031/onFrameClose", "#1001030/handleEscapeKey", "#1001029/printVMSize", "#1001026/eq", "#1001024/internAll", "#1001017/matcher", "#1001012/getSnippetTitle", "#1001008/roundUpTo", "#1001007/safeSubstring", "#1001032/clone", "#1000999/asList", "#1000998/md5", "#1000994/loadFont", "#1000984/makeServerSocket", "#1000968/loadLibrary", "#1000962/suckFromChat", "#1000962/suckFromChatNoHistory", "#1000961/isInstanceX", "#1000960/listUserThreadsWithStackTraces", "#1000959/listThreads", "#1000955/autoReportToChatOff", "#1000980/isAutoReportToChatOn", "#1000952/die", "#1000950/autoReportToChat", "#1000946/getJavaX", "#1000942/urldecode", "#1000940/exit", "#1000938/synchronizedList", "#1000937/chatSend", "#1000935/reportToChat", "#1000932/waitForChatServer", "#1000931/portIsBound", "#1000929/startChatServerIfNotUp", "#1000921/makeFrame", "#1000918/smartJoin", "#1000916/slte", "#1000909/killMyself", "#1000908/runCmdWithTerminal", "#1000906/htmlgetparams", "#1000905/error", "#1000892/dropAllTags", "#1000891/setOpt", "#1000877/installTimer", "#1000869/randomID", "#1000862/tagIs", "#1000864/isAndroid", "#1000861/isUpperCase", "#1000860/equals", "#1000856/htmlunquote", "#1000855/backtick", "#1000853/backtickJavax", "#1000851/linkFrom", "#1000848/splitScript", "#1000844/copyStream", "#1000843/copyFile", "#1000841/printMyIPs", "#1000838/classicNohupJavax", "#1000835/topToBottomPanel", "#1000832/bashQuote", "#1000830/winQuote", "#1000829/isWindows", "#1000828/nohup", "#1000827/mkdirsForFile", "#1000826/withLabel", "#1000814/dropPunctuation", "#1000813/tokensToLowerCase", "#1000812/match2", "#1000811/parseInt", "#1000808/isPortOpen", "#1000983/installHelloMessage", "#1000801/now", "#1000800/startTiming", "#1000800/stopTiming", "#1000799/findField", "#1000798/dropFirst", "#1000793/htmldecode", "#1000784/sort", "#1000779/wakeUp", "#1000769/javaTokPlusPeriod", "#1000754/uploadData", "#1000754/uploadDataSuperHigh", "#1000750/base64encode", "#1000744/loadBinaryFile", "#1000741/uploadImage", "#2000554/binaryUrlencode", "#1000737/kevin", // hmm, this has so many library dependencies "#1000736/sleep", "#1000734/find", "#1000735/getBattery", "#1000729/copyStream", "#1000705/drop", "#1000719/dropLast", "#1000692/randomLetters", "#1000689/processSilent", "#1000688/javaTok", "#1000685/matchTokensList", "#1000679/gunzipToText", "#1000677/loadBinarySnippet", "#1000676/getGlobalCache", "#1000675/loadDataSnippetImpl", "#1000672/indent", "#1000670/htmlcoarsetok", "#1000668/callMain", "#1000664/mysqlUnquote", "#1000663/processDebug", "#1000661/process", "#1000658/print", "#1001042/saveTextFile", "#1001049/loadTextFile", "#1001108/readTextFile", "#1002380/loadMainJava", "#1001807/saveMainJava", "#1001950/toLines", "#2000478/toLinesTrim", "#1000641/toLinesFullTrim", "#1002398/fromLines", "#1000997/loadSnippet", "#1000535/loadSnippetAndTitle", "#1000520/isSnippetID", "#2000331/makeJavaStringLiteral", "#1000893/popup", "#2000367/popupError", "#2000368/exitOnFrameClose", "#2000378/commonPrefix", "#2000379/commonSuffix", "#1001735/unquote", // formerly, 471 "#2000444/cncToLines", "#2000460/bytesToHex", "#1000837/loadBinaryPage", "#1001113/saveBinaryFile", "#1001561/rtrim", "#1000879/loadPage", "#1000879/loadPageSilently", "#2000489/matchAll", "#2000490/debugOn", "#2000491/getClass", "#1000630/call", "#1000963/hotwire", "#1000415/set", // we should really improve the function invocation detection, this is probably included too often... "#1000441/setWidgetColor", "#1000442/goToHomeScreen", "#2000502/patternQuote", "#1000810/join", "#1002222/repeat", "#1001913/unnull", "#2000510/formatDouble", "#1001958/loadImage", // needs the image classes "#1000659/fail", "#1000524/structureSize", "#1000565/doPost", "#1000566/ntUpload", "#1000567/isInteger", "#1000568/computerID", "#1000569/userHome", // TODO: adapt for Android! "#1000570/makeRandomID", "#1000580/urlencode", "#1000581/findSnippetsNamed", "#1000582/findSnippetNamed", "#1000588/javaQuote", "#1000593/jsonTok", "#1000620/jsonDecode", "#1000595/compileAndLoadMainClass", "#1000598/isSafeCompilable", "#1000601/updateMyCommentOnSnippet", "#1000608/moveImportsUp", "#1000609/updateWidgetWithText", "#1000619/get", "#1000619/get_raw", "#1000621/getSnippetComments", "#1000628/first", "#1001386/structure", // v2 "#1000644/shorten", "#1000646/isJavaxSafe", "#1000888/isJavaCompilable", "#1000647/mysqlTok", "#1000657/indexOfIgnoreCase", "#1000708/parseSnippetID", "#1000709/formatSnippetID", "#1000711/shortenSnippetID", "#1000716/confused", "#1000717/todo", "#1000889/getStackTrace" }; public static void main(String[] args) throws IOException { long startTime = now(); String s = loadMainJava(); Map sf = new HashMap(); for (String x : standardFunctions) { String[] f = x.split("/"); sf.put(f[0], f[1]); } for (int i = 0; ; i++) { Set defd = new HashSet(findFunctions(s)); List tok = javaTok(s); // changes tok List invocations = findInvocations(tok, sf); s = join(tok); List needed = diff(invocations, defd); print("Functions needed: " + needed); if (needed.isEmpty()) break; for (String x : needed) { String id = sf.get(x); System.out.println("Adding function: " + x + " (" + id + ")"); s = addFunction(s, id); } defd = new HashSet(findFunctions(s)); for (String x : needed) if (!defd.contains(x)) fail("Function not defined properly: " + x); System.out.println("Iteration " + (i+2)); if (i >= 1000) fail("Too many iterations"); } saveMainJava(s); print("629: " + (now()-startTime) + " ms"); } static List findInvocations(List tok, Map sf) { int i; List l = new ArrayList(); while ((i = jfind(tok, "please include function *.")) >= 0) { String fname = tok.get(i+6); l.add(fname); clearAllTokens(tok.subList(i, i+10)); } boolean result = false; for (i = 1; i+2 < tok.size(); i += 2) { String f = tok.get(i); if (!isIdentifier(f)) continue; if ((i == 1 || !tok.get(i-2).equals(".")) && tok.get(i+2).equals("(")) { boolean inSF = sf.containsKey(f); if (debug) print("Possible invocation: " + f + ", inSF: " + inSF); if (inSF) l.add(f); } } return l; } static boolean substringIs(String s, int i, String pat) { return i >= 0 && i+pat.length() < s.length() && s.substring(i, i+pat.length()).equals(pat); } // OK, this should be fast enough. static List findFunctions(String src) { int idx = src.indexOf("main {"); // yes it's a hack... if (idx >= 0) src = src.substring(idx); Pattern pattern = Pattern.compile("static[^={]*\\s+(\\w+)\\("); //System.out.println("Scanning for functions"); List functions = new ArrayList(); for (String line : toLines(src)) { Matcher matcher = pattern.matcher(line); if (matcher.find()) { String f = matcher.group(1); functions.add(f); //System.out.println("Function found: " + f); } } return functions; } public static String addFunction(String s, String fID) throws IOException { int i = s.lastIndexOf('}'); String function = loadSnippet(fID); return s.substring(0, i) + "\n" + function +"\n" + s.substring(i); } public static List toLines(String s) { List lines = new ArrayList(); int start = 0; while (true) { int i = toLines_nextLineBreak(s, start); if (i < 0) { if (s.length() > start) lines.add(s.substring(start)); break; } lines.add(s.substring(start, i)); if (s.charAt(i) == '\r' && i+1 < s.length() && s.charAt(i+1) == '\n') i += 2; else ++i; start = i; } return lines; } private static int toLines_nextLineBreak(String s, int start) { for (int i = start; i < s.length(); i++) { char c = s.charAt(i); if (c == '\r' || c == '\n') return i; } return -1; } static String mainJava; static String loadMainJava() throws IOException { if (mainJava != null) return mainJava; return loadTextFile("input/main.java", ""); } static void saveMainJava(String s) throws IOException { if (mainJava != null) mainJava = s; else saveTextFile("output/main.java", s); } static void saveMainJava(List tok) throws IOException { saveMainJava(join(tok)); } static String charsetForTextFiles = "UTF-8"; public static String loadTextFile(String fileName, String defaultContents) throws IOException { if (!new File(fileName).exists()) return defaultContents; FileInputStream fileInputStream = new FileInputStream(fileName); InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, charsetForTextFiles); return loadTextFile(inputStreamReader); } public static String loadTextFile(Reader reader) throws IOException { StringBuilder builder = new StringBuilder(); try { BufferedReader bufferedReader = new BufferedReader(reader); String line; while ((line = bufferedReader.readLine()) != null) builder.append(line).append('\n'); } finally { reader.close(); } return builder.length() == 0 ? "" : builder.substring(0, builder.length()-1); } /** writes safely (to temp file, then rename) */ public static void saveTextFile(String fileName, String contents) throws IOException { File file = new File(fileName); File parentFile = file.getParentFile(); if (parentFile != null) parentFile.mkdirs(); String tempFileName = fileName + "_temp"; FileOutputStream fileOutputStream = new FileOutputStream(tempFileName); OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, charsetForTextFiles); PrintWriter printWriter = new PrintWriter(outputStreamWriter); printWriter.print(contents); printWriter.close(); if (file.exists() && !file.delete()) throw new IOException("Can't delete " + fileName); if (!new File(tempFileName).renameTo(file)) throw new IOException("Can't rename " + tempFileName + " to " + fileName); } public static String loadSnippet(String snippetID) throws IOException { return loadSnippet(snippetID, preferCached); } public static String loadSnippet(String snippetID, boolean preferCached) throws IOException { return loadSnippet(parseSnippetID(snippetID), preferCached); } public static long parseSnippetID(String snippetID) { return Long.parseLong(shortenSnippetID(snippetID)); } private static String shortenSnippetID(String snippetID) { if (snippetID.startsWith("#")) snippetID = snippetID.substring(1); String httpBlaBla = "http://tinybrain.de/"; if (snippetID.startsWith(httpBlaBla)) snippetID = snippetID.substring(httpBlaBla.length()); return snippetID; } public static boolean isSnippetID(String snippetID) { snippetID = shortenSnippetID(snippetID); return isInteger(snippetID) && Long.parseLong(snippetID) != 0; } public static boolean isInteger(String s) { return Pattern.matches("\\-?\\d+", s); } static boolean preferCached = false; public static String loadSnippet(long snippetID) throws IOException { return loadSnippet(snippetID, preferCached); } public static String loadSnippet(long snippetID, boolean preferCached) throws IOException { if (preferCached) { initSnippetCache(); String text = DiskSnippetCache_get(snippetID); if (text != null) return text; } String text; try { URL url = new URL("http://tinybrain.de:8080/getraw.php?id=" + snippetID); text = loadPage(url); } catch (FileNotFoundException e) { throw new IOException("Snippet #" + snippetID + " not found or not public"); } try { initSnippetCache(); DiskSnippetCache_put(snippetID, text); } catch (IOException e) { System.err.println("Minor warning: Couldn't save snippet to cache (" + DiskSnippetCache_getDir() + ")"); } return text; } private static String loadPage(URL url) throws IOException { System.out.println("Loading: " + url.toExternalForm()); URLConnection con = url.openConnection(); return loadPage(con, url); } public static String loadPage(URLConnection con, URL url) throws IOException { String contentType = con.getContentType(); if (contentType == null) throw new IOException("Page could not be read: " + url); //Log.info("Content-Type: " + contentType); String charset = guessCharset(contentType); Reader r = new InputStreamReader(con.getInputStream(), charset); StringBuilder buf = new StringBuilder(); while (true) { int ch = r.read(); if (ch < 0) break; //Log.info("Chars read: " + buf.length()); buf.append((char) ch); } return buf.toString(); } public static String guessCharset(String contentType) { Pattern p = Pattern.compile("text/html;\\s+charset=([^\\s]+)\\s*"); Matcher m = p.matcher(contentType); /* If Content-Type doesn't match this pre-conception, choose default and hope for the best. */ return m.matches() ? m.group(1) : "ISO-8859-1"; } static File DiskSnippetCache_dir; public static void initDiskSnippetCache(File dir) { DiskSnippetCache_dir = dir; dir.mkdirs(); } public static synchronized String DiskSnippetCache_get(long snippetID) throws IOException { return loadTextFile(DiskSnippetCache_getFile(snippetID).getPath(), null); } private static File DiskSnippetCache_getFile(long snippetID) { return new File(DiskSnippetCache_dir, "" + snippetID); } public static synchronized void DiskSnippetCache_put(long snippetID, String snippet) throws IOException { saveTextFile(DiskSnippetCache_getFile(snippetID).getPath(), snippet); } public static File DiskSnippetCache_getDir() { return DiskSnippetCache_dir; } public static void initSnippetCache() { if (DiskSnippetCache_dir == null) initDiskSnippetCache(new File(System.getProperty("user.home"), ".tinybrain/snippet-cache")); } static RuntimeException fail() { throw new RuntimeException("fail"); } static RuntimeException fail(Object msg) { throw new RuntimeException(String.valueOf(msg)); } // replacement for class JavaTok // maybe incomplete, might want to add floating point numbers // todo also: extended multi-line strings static List javaTok(String s) { List tok = new ArrayList(); int l = s.length(); int i = 0; while (i < l) { int j = i; char c; String cc; // scan for whitespace while (j < l) { c = s.charAt(j); cc = s.substring(j, Math.min(j+2, l)); if (c == ' ' || c == '\t' || c == '\r' || c == '\n') ++j; else if (cc.equals("/*")) { do ++j; while (j < l && !s.substring(j, Math.min(j+2, l)).equals("*/")); j = Math.min(j+2, l); } else if (cc.equals("//")) { do ++j; while (j < l && "\r\n".indexOf(s.charAt(j)) < 0); } else break; } tok.add(s.substring(i, j)); i = j; if (i >= l) break; c = s.charAt(i); // cc is not needed in rest of loop body cc = s.substring(i, Math.min(i+2, l)); // scan for non-whitespace if (c == '\'' || c == '"') { char opener = c; ++j; while (j < l) { if (s.charAt(j) == opener) { ++j; break; } else if (s.charAt(j) == '\\' && j+1 < l) j += 2; else ++j; } } else if (Character.isJavaIdentifierStart(c)) do ++j; while (j < l && Character.isJavaIdentifierPart(s.charAt(j))); else if (Character.isDigit(c)) { do ++j; while (j < l && Character.isDigit(s.charAt(j))); if (j < l && s.charAt(j) == 'L') ++j; // Long constants like 1L } else if (cc.equals("[[")) { do ++j; while (j+1 < l && !s.substring(j, j+2).equals("]]")); j = Math.min(j+2, l); } else ++j; tok.add(s.substring(i, j)); i = j; } if ((tok.size() % 2) == 0) tok.add(""); return tok; } static List javaTok(List tok) { return javaTok(join(tok)); } public static String join(String glue, Iterable strings) { StringBuilder buf = new StringBuilder(); Iterator i = strings.iterator(); if (i.hasNext()) { buf.append(i.next()); while (i.hasNext()) buf.append(glue).append(i.next()); } return buf.toString(); } public static String join(String glue, String[] strings) { return join(glue, Arrays.asList(strings)); } public static String join(Iterable strings) { return join("", strings); } public static String join(String[] strings) { return join("", strings); } // leaves tok properly tokenized // returns true iff anything was replaced static boolean jreplace(List tok, String in, String out) { return jreplace(tok, in, out, false, true); } static boolean jreplace(List tok, String in, String out, boolean ignoreCase, boolean reTok) { List tokin = javaTok(in); replaceSublist(tokin, litlist("<", "", "quoted", "", ">"), litlist("")); replaceSublist(tokin, litlist("<", "", "id", "", ">"), litlist("")); boolean anyChange = false; for (int n = 0; n < 10000; n++) { int i = findCodeTokens(tok, ignoreCase, toStringArray(codeTokensOnly(tokin))); if (i < 0) { if (anyChange && reTok) replaceCollection(tok, javaTok(tok)); return anyChange; } List subList = tok.subList(i-1, i+l(tokin)-1); // N to N String expansion = jreplace_expandRefs(out, subList); clearAllTokens(tok.subList(i, i+l(tokin)-2)); // code to code tok.set(i, expansion); anyChange = true; } throw fail("woot? 10000!"); } // "$1" is first code token, "$2" second code token etc. static String jreplace_expandRefs(String s, List tokref) { List tok = javaTok(s); for (int i = 1; i < l(tok)-2; i += 2) { if (tok.get(i).startsWith("$") && isInteger(tok.get(i).substring(1))) { String x = tokref.get(-1+parseInt(tok.get(i).substring(1))*2); tok.set(i, x); } } return join(tok); } static void replaceToken(List tok, String in, String out) { renameToken(tok, in, out); } static void replaceCollection(Collection dest, Collection src) { dest.clear(); dest.addAll(src); } static ArrayList litlist(A... a) { return new ArrayList(Arrays.asList(a)); } static List codeTokensOnly(List tok) { List l = new ArrayList(); for (int i = 1; i < tok.size(); i += 2) l.add(tok.get(i)); return l; } static void replaceSublist(List l, List x, List y) { int i = 0; while (true) { i = indexOfSubList(l, x, i); if (i < 0) return; // It's inefficient :D for (int j = 0; j < l(x); j++) l.remove(i); l.addAll(i, y); i += l(y); } } static int l(Object[] array) { return array == null ? 0 : array.length; } static int l(Collection c) { return c == null ? 0 : c.size(); } static int l(Map m) { return m == null ? 0 : m.size(); } static int l(String s) { return s == null ? 0 : s.length(); } static int parseInt(String s) { return Integer.parseInt(s); } static void renameToken(List tok, String in, String out) { int renames = 0; for (int i = 1; i < tok.size(); i += 2) { if (tok.get(i).equals(in)) { tok.set(i, out); ++renames; } } } static String[] toStringArray(List list) { return list.toArray(new String[list.size()]); } static String[] toStringArray(Object o) { if (o instanceof String[]) return (String[]) o; else if (o instanceof List) return toStringArray((List) o); else throw fail("Not a list or array: " + o); } static int findCodeTokens(List tok, String... tokens) { return findCodeTokens(tok, 1, false, tokens); } static int findCodeTokens(List tok, boolean ignoreCase, String... tokens) { return findCodeTokens(tok, 1, ignoreCase, tokens); } static int findCodeTokens(List tok, int startIdx, boolean ignoreCase, String... tokens) { outer: for (int i = startIdx | 1; i+tokens.length*2-2 < tok.size(); i += 2) { for (int j = 0; j < tokens.length; j++) { String p = tokens[j], t = tok.get(i+j*2); boolean match; if (eq(p, "*")) match = true; else if (eq(p, "")) match = isQuoted(t); else if (eq(p, "")) match = isIdentifier(t); else match = ignoreCase ? eqic(p, t) : eq(p, t); if (!match) continue outer; } return i; } return -1; } static void clearAllTokens(List tok) { for (int i = 0; i < tok.size(); i++) tok.set(i, ""); } static void clearAllTokens(List tok, int i, int j) { for (; i < j; i++) tok.set(i, ""); } static boolean isIdentifier(String s) { return isJavaIdentifier(s); } static boolean eqic(String a, String b) { if ((a == null) != (b == null)) return false; if (a == null) return true; return a.equalsIgnoreCase(b); } // supports the usual quotings (', ", variable length double brackets) static boolean isQuoted(String s) { if (s.startsWith("'") || s.startsWith("\"")) return true; if (!s.startsWith("[")) return false; int i = 1; while (i < s.length() && s.charAt(i) == '=') ++i; return i < s.length() && s.charAt(i) == '['; //return Pattern.compile("^\\[=*\\[").matcher(s).find(); } static boolean eq(Object a, Object b) { if (a == null) return b == null; if (a.equals(b)) return true; if (a instanceof BigInteger) { if (b instanceof Integer) return a.equals(BigInteger.valueOf((Integer) b)); if (b instanceof Long) return a.equals(BigInteger.valueOf((Long) b)); } return false; } static boolean isJavaIdentifier(String s) { if (s.length() == 0 || !Character.isJavaIdentifierStart(s.charAt(0))) return false; for (int i = 1; i < s.length(); i++) if (!Character.isJavaIdentifierPart(s.charAt(i))) return false; return true; } static int indexOfSubList(List x, List y, int i) { outer: for (; i+l(y) <= l(x); i++) { for (int j = 0; j < l(y); j++) if (neq(x.get(i+j), y.get(j))) continue outer; return i; } return -1; } static boolean neq(Object a, Object b) { return !eq(a, b); } static long now() { return System.currentTimeMillis(); } static void print(String s) { System.out.println(s); } static List diff(List a, Set b) { List l = new ArrayList(); for (String s : a) if (!b.contains(s)) l.add(s); return l; } static int jfind(List tok, String in) { List tokin = javaTok(in); replaceSublist(tokin, litlist("<", "", "quoted", "", ">"), litlist("")); replaceSublist(tokin, litlist("<", "", "id", "", ">"), litlist("")); return findCodeTokens(tok, false, toStringArray(codeTokensOnly(tokin))); } }