Rosetta Code/Find unimplemented tasks: Difference between revisions
(→{{header|AutoHotkey}}: typo in template-'link') |
(→{{header|Ruby}}: determine if omitted, sort by time) |
||
Line 453: | Line 453: | ||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
Finds tasks that are either not implemented or omitted. Sorts by task creation time. |
|||
Uses the <code>RosettaCode</code> module from [[Count programming examples#Ruby]] |
Uses the <code>RosettaCode</code> module from [[Count programming examples#Ruby]] |
||
<lang ruby>require 'rosettacode' |
<lang ruby>require 'rosettacode' |
||
require 'time' |
|||
module RosettaCode |
module RosettaCode |
||
def |
def self.get_unimplemented(lang) |
||
programming_tasks = [] |
programming_tasks = [] |
||
category_members("Programming_Tasks") {|task| programming_tasks << task} |
|||
lang_tasks = [] |
lang_tasks = [] |
||
category_members(lang) {|task| lang_tasks << task} |
|||
⚫ | |||
lang_tasks_omit = [] |
|||
category_members("#{lang}/Omit") {|task| lang_tasks_omit << task} |
|||
⚫ | |||
end |
end |
||
def self.created_time(title) |
|||
url = get_api_url({ |
|||
"action" => "query", |
|||
"titles" => title, |
|||
"format" => "xml", |
|||
"rvlimit" => 500, |
|||
"prop" => "revisions", |
|||
"rvprop" => "timestamp" |
|||
}) |
|||
doc = REXML::Document.new open(url) |
|||
REXML::XPath.each(doc, "//rev").collect do |node| |
|||
Time.parse( node.attribute("timestamp").value ) |
|||
end.min |
|||
end |
|||
end |
end |
||
puts Time.now |
|||
lang = "Ruby" |
lang = ARGV[0] || "Ruby" |
||
unimplemented = RosettaCode. |
unimplemented, omitted = RosettaCode.get_unimplemented(lang) |
||
puts "#{lang} has #{unimplemented.length} unimplemented tasks:" |
|||
unimplemented.collect {|title| [title, RosettaCode.created_time(title)]} . |
|||
puts unimplemented.join("\n")</lang> |
|||
sort_by {|e| e[1]} . |
|||
each do |title, date| |
|||
puts "%s %6s %s" % [ |
|||
date.strftime("%Y-%m-%d"), |
|||
omitted.include?(title) ? "[omit]" : "" , |
|||
title |
|||
] |
|||
end |
|||
</lang> |
|||
Output for Ruby |
|||
<pre style="height: 32ex; overflow: scroll">2010-04-05 11:08:07 -0500 |
|||
2007-01-14 Table creation |
|||
2007-01-25 [omit] Pointers and references |
|||
2007-02-04 SQL-based authentication |
|||
2007-02-09 Metered concurrency |
|||
2007-02-27 [omit] Address of a variable |
|||
2007-02-27 [omit] Variable size/Set |
|||
2007-02-27 Variable size/Get |
|||
2007-06-08 OpenGL |
|||
2007-06-08 HTTPS/Authenticated |
|||
2007-11-06 Pattern matching |
|||
2007-11-08 [omit] Parametric polymorphism |
|||
2007-11-13 Special characters |
|||
2007-12-11 Arithmetic evaluation |
|||
2007-12-21 [omit] Proof |
|||
2007-12-24 Plot coordinate pairs |
|||
2007-12-24 Polynomial regression |
|||
2007-12-24 Compare sorting algorithms' performance |
|||
2008-03-27 Dragon curve |
|||
2008-03-28 Formal power series |
|||
2008-09-11 RCRPG |
|||
2008-11-02 Active object |
|||
2008-11-13 Window creation/X11 |
|||
2008-12-05 [omit] Constrained genericity |
|||
2009-02-17 Rendezvous |
|||
2009-03-22 Arena storage pool |
|||
2009-05-23 Ray-casting algorithm |
|||
2009-05-26 [omit] Memory allocation |
|||
2009-05-26 Simulate input/Mouse |
|||
2009-05-27 Mouse position |
|||
2009-05-27 Keyboard macros |
|||
2009-05-27 Window management |
|||
2009-05-27 Color of a screen pixel |
|||
2009-06-01 HTTPS/Client-authenticated |
|||
2009-06-02 Simulate input/Keyboard |
|||
2009-06-08 [omit] Create an object at a given address |
|||
2009-06-10 Events |
|||
2009-06-10 Scope modifiers |
|||
2009-08-09 Verify distribution uniformity/Chi-squared test |
|||
2009-08-11 Call a function from a foreign language |
|||
2009-08-12 Safe addition |
|||
2009-12-05 Rate counter |
|||
2010-01-02 Loading Animated 3D Data |
|||
2010-01-06 Catmull–Clark subdivision surface |
|||
2010-01-21 Hough transform |
|||
2010-01-25 Compile-time calculation |
|||
2010-02-14 Knapsack problem/Bounded |
|||
2010-02-21 Deconvolution/1D |
|||
2010-02-23 Deconvolution/2D+ |
|||
2010-02-24 Knapsack problem/Continuous |
|||
2010-03-23 Sutherland-Hodgman polygon clipping |
|||
2010-03-23 Find Common Directory Path</pre> |
|||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
Revision as of 15:07, 5 April 2010
You are encouraged to solve this task according to the task description, using any language you may know.
Given the name of a language on Rosetta Code, find all tasks which are not implemented in that language.
Note: Implementations should allow for fetching more data than can be returned in one request to Rosetta Code.
AutoHotkey
<lang AutoHotkey>MsgBox % getUnimplemented("AutoHotkey") MsgBox % getUnimplemented("Python")
getUnimplemented(category) {
url := "http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:"
. category . "&cmlimit=500&format=xml"
url2 := "http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:Programming_Tasks&cmlimit=500&format=xml"
UrlDownloadToFile, %url%, unimplemented.html UrlDownloadToFile, %url2%, alltasks.html FileRead, category2, unimplemented.html FileRead, alltasks, alltasks.html pos = 1 reg = title="[^"]+" ; " While (pos := RegexMatch(alltasks, reg, title, pos)) { StringReplace, title, title, title= StringReplace, title, title, `", ,All ; " If !InStr(category2, title) todo .= title . "`n" pos += 1 } Return todo
}</lang>
C#
Using JSON (not parsed, just Regex.)
<lang csharp>using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; using System.Net;
class Program {
static string[] GetTitlesFromCategory(string category) { string content = new WebClient().DownloadString( String.Format("http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:{0}&cmlimit=500&format=json", category) );
return new Regex("\"title\":\"(.+?)\"").Matches(content).Cast<Match>().Select(x => x.Groups[1].Value).ToArray(); }
static string[] GetUnimplementedTasksFromLanguage(string language) { List<string> alltasks = GetTitlesFromCategory("Programming_Tasks").ToList(); List<string> lang = GetTitlesFromCategory(language).ToList();
return alltasks.Where(x => !lang.Contains(x)).ToArray(); }
static void Main(string[] args) { string[] unimpl = GetUnimplementedTasksFromLanguage(args[0]);
foreach (string i in unimpl) Console.WriteLine(i); }
}</lang>
E
Using JSON.
<lang e>#!/usr/bin/env rune
- NOTE: This program will not work in released E, because TermL is an
- imperfect superset of JSON in that version: it does not accept "\/".
- If you build E from the latest source in SVN then it will work.
- Usage: rosettacode-cat-subtract.e [<lang e>]
- Prints a list of tasks which have not been completed in the language.
- If unspecified, the default language is E.
pragma.syntax("0.9") pragma.enable("accumulator")
def termParser := <import:org.quasiliteral.term.makeTermParser> def jURLEncoder := <unsafe:java.net.makeURLEncoder>
def urlEncode(text) {
return jURLEncoder.encode(text, "UTF-8")
}
/** Convert JSON-as-term-tree to the corresponding natural E data structures. */ def jsonTermToData(term) {
switch (term) {
# JSON object to E map match term`{@assocs*}` { return accum [].asMap() for term`@{key :String}: @valueJson` in assocs { _.with(key, jsonTermToData(valueJson)) } }
# JSON array to E list match term`[@elements*]` { return accum [] for elem in elements { _.with(jsonTermToData(elem)) } } # Literals just need to be coerced match lit :any[String, int, float64] { return lit } # Doesn't support true/false/null, but we don't need that for this application. }
}
def fetchCategoryAccum(name, membersSoFar :Set, extraArgs) {
stderr.println(`Fetching Category:$name $extraArgs...`) def categoryAPIResource := <http>[`//rosettacode.org/w/api.php?` + `action=query&list=categorymembers&cmtitle=Category:${urlEncode(name)}&` + `format=json&cmlimit=500&cmprop=title$extraArgs`] def members := when (def responseJSON := categoryAPIResource <- getTwine()) -> { # stderr.println(`Fetched Category:$name $extraArgs, parsing...`) def response := jsonTermToData(termParser(responseJSON))
# stderr.println(`Parsed Category:$name $extraArgs response, extracting data...`) def [ "query" => ["categorymembers" => records], "query-continue" => continueData := null ] := response def members := accum membersSoFar for record in records { _.with(record["title"]) } switch (continueData) { match ==null { stderr.println(`Got all ${members.size()} for Category:$name.`) members } match ["categorymembers" => ["cmcontinue" => continueParam]] { stderr.println(`Fetched ${members.size()} members for Category:$name...`) fetchCategoryAccum(name, members, `&cmcontinue=` + urlEncode(continueParam)) } } } catch p { throw(p) } return members
}
def fetchCategory(name) {
return fetchCategoryAccum(name, [].asSet(), "")
}
- Interpret program arguments
def lang := switch (interp.getArgs()) {
match [lang] { lang } match [] { "E" }
}
- Fetch categories
when (def allTasks := fetchCategory("Programming_Tasks"),
def doneTasks := fetchCategory(lang), def omitTasks := fetchCategory(lang + "/Omit") ) -> { # Compute difference and report def notDoneTasks := allTasks &! (doneTasks | omitTasks) println() println("\n".rjoin(notDoneTasks.getElements().sort()))
} catch p {
# Whoops, something went wrong stderr.println(`$p${p.eStack()}`)
}</lang>
Haskell
from HackageDB
<lang haskell>import Network.Browser import Network.HTTP import Network.URI import Data.List import Data.Maybe import Text.XML.Light import Control.Arrow import Data.Char
getRespons url = do
rsp <- Network.Browser.browse $ do setAllowRedirects True setOutHandler $ const (return ()) -- quiet request $ getRequest url return $ rspBody $ snd rsp
replaceWithSpace c = (\x -> if c==x then ' ' else x)
encl = chr 34
unimpTasks lang = do
allTasks <- getRespons "http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:Programming_Tasks&cmlimit=500&format=xml" impl <- getRespons ( "http://rosettacode.org/json/isb/" ++ lang ++ ".json") let langxx = map (map(replaceWithSpace '_')) $ filter (/=",") $ words $ map (replaceWithSpace encl ) $ init $ drop 1 impl xml = onlyElems $ parseXML allTasks allxx = concatMap (map (fromJust.findAttr (unqual "title")). filterElementsName (== unqual "cm")) xml mapM_ putStrLn $ sort $ allxx \\ langxx</lang>
J
Solution: <lang j>require 'strings web/gethttp'
findUnimpTasks=: ('Programming_Tasks' -.&getCategoryMembers ,&'/Omit') ([ #~ -.@e.) getCategoryMembers
getTagContents=: dyad define
'starttag endtag'=. x ('\' -.~ endtag&taketo)&.>@(starttag&E. <@((#starttag)&}.);.1 ]) y
)
NB. RosettaCode Utilities parseTitles=: ('"title":"';'"')&getTagContents parseCMcontinue=:('"cmcontinue":"';'"')&getTagContents getCMcontquery=: ('&cmcontinue=' , urlencode)^:(0 < #)@>@parseCMcontinue
getCategoryMembers=: monad define
buildqry=. 'action=query&list=categorymembers&cmtitle=Category:' , ,&'&cmlimit=500&format=json' url=.'http://www.rosettacode.org/w/api.php' uri=. url ,'?', buildqry urlencode y catmbrs=. qrycont=. whilst. #qrycont=. getCMcontquery jsondat do. jsondat=. gethttp uri , qrycont catmbrs=. catmbrs, parseTitles jsondat end. catmbrs
)</lang>
Example Usage: <lang j> 4{. findUnimpTasks 'J' NB. get first 4 unimplemented tasks for J +-------------+--------------+----------------+------------------------------+ |Active object|Atomic updates|Basic input loop|Call foreign language function| +-------------+--------------+----------------+------------------------------+</lang>
Oz
By parsing XML and using an XPath-like mechanism: <lang oz>declare
[HTTPClient] = {Link ['x-ozlib://mesaros/net/HTTPClient.ozf']} [XMLParser] = {Link ['x-oz://system/xml/Parser.ozf']}
fun {FindUnimplementedTasks Language} AllTasks = {FindCategory "Programming Tasks"} LangTasks = {FindCategory Language} in {ListDiff AllTasks LangTasks} end fun {FindCategory Cat} CatUrl = "http://www.rosettacode.org/mw/api.php?action=query" #"&list=categorymembers" #"&cmtitle=Category:"#{PercentEncode Cat} #"&cmlimit=500&format=xml"
fun {Loop CMContinue} [_ Doc] = {Parse {GetPage CatUrl#CMContinue}} Titles = {XPath Doc [api query categorymembers cm {Attribute title}]} in case {XPath Doc [api 'query-continue' categorymembers {Attribute cmcontinue}]} of nil then Titles [] [NewCMContinueAtom] then NewCMContinue = {PercentEncode {Atom.toString NewCMContinueAtom}} in {Append Titles {Loop "&cmcontinue="#NewCMContinue}} end end in {Loop nil} end
%% XPath emulation fun {XPath Doc Path} P|Pr = Path in Doc.name = P %% assert {FoldL Pr XPathStep [Doc]} end
Nothing = {NewName} fun {NotNothing X} X \= Nothing end fun {XPathStep Elements P} if {Atom.is P} then {FilteredChildren Elements P} elseif {Procedure.is P} then {Filter {Map Elements P} NotNothing} end end %% A flat list of all Type-children of all Elements. fun {FilteredChildren Elements Type} {Flatten {Map Elements fun {$ E} {Filter E.children fun {$ X} case X of element(name:!Type ...) then true else false end end} end}} end fun {Attribute Attr} fun {$ Element} case {Filter Element.attributes fun {$ A} A.name == Attr end} of [A] then A.value else Nothing end end end
%% GetPage Client = {New HTTPClient.urlGET init(inPrms(toFile:false toStrm:true) _)} fun {GetPage RawUrl} Url = {VirtualString.toString RawUrl} OutParams in {Client getService(Url ?OutParams ?_)} OutParams.sOut end fun {PercentEncode Xs} case Xs of nil then nil [] X|Xr then if {Char.isDigit X} orelse {Member X [&- &_ &. &~]} orelse X >= &a andthen X =< &z orelse X >= &z andthen X =< &Z then X|{PercentEncode Xr} else {Append &%|{ToHex2 X} {PercentEncode Xr}} end end end fun {ToHex2 X} [{ToHex1 X div 16} {ToHex1 X mod 16}] end fun {ToHex1 X} if X >= 0 andthen X =< 9 then &0 + X elseif X >= 10 andthen X =< 15 then &A + X - 10 end end
%% Parse local Parser = {New XMLParser.parser init} in fun {Parse Xs} {Parser parseVS(Xs $)} end end
fun {ListDiff Xs Ys} {FoldL Ys List.subtract Xs} end
in
%% show tasks not implemented in Oz {ForAll {FindUnimplementedTasks "Oz"} System.showInfo}</lang>
Perl
Using JSON (not parsed, just Regex.)
<lang perl>use LWP::Simple 'get';
my $fmt = 'http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:%s&cmlimit=500&format=json'; my $lang = shift
or die "No language given.\n";
sub urlencode
{join , map {sprintf '%%%02x', ord} split //, shift}
sub tasks
{my $category = urlencode shift; my @tasks; my $json = get sprintf $fmt, $category; for (;;) {push @tasks, $json =~ /"title":"(.+?)"}/g; $json =~ /"cmcontinue":"(.+?)"}/ or last; $json = get sprintf $fmt . '&cmcontinue=%s', $category, urlencode $1;} return @tasks;}
my @all = tasks 'Programming_Tasks'; my %lang = map {$_, 1} tasks $lang
or die "No such category.\n";
$lang{$_} or print "$_\n"
foreach @all;</lang>
See also: User:ImplSearchBot/Code
Python
Using XML.
<lang python>import xml.dom.minidom import urllib, sys
def findrc(category):
name = "http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:%s&cmlimit=500&format=xml" % urllib.quote(category) cmcontinue, titles = , [] while True: u = urllib.urlopen(name + cmcontinue) xmldata = u.read() u.close() x = xml.dom.minidom.parseString(xmldata) titles += [i.getAttribute("title") for i in x.getElementsByTagName("cm")] cmcontinue = filter( None, (urllib.quote(i.getAttribute("cmcontinue")) for i in x.getElementsByTagName("categorymembers")) ) if cmcontinue: cmcontinue = '&cmcontinue=' + cmcontinue[0] else: break return titles
alltasks = findrc("Programming_Tasks") lang = findrc(sys.argv[1])
for i in [i for i in alltasks if i not in lang]:
print i</lang>
R
<lang R>library(XML) find.unimplemented.tasks <- function(lang="R"){ PT <- xmlInternalTreeParse( paste("http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:Programming_Tasks&cmlimit=500&format=xml",sep="") ) PT.nodes <- getNodeSet(PT,"//cm") PT.titles = as.character( sapply(PT.nodes, xmlGetAttr, "title") ) language <- xmlInternalTreeParse( paste("http://www.rosettacode.org/w/api.php?action=query&list=categorymembers&cmtitle=Category:", lang, "&cmlimit=500&format=xml",sep="") ) lang.nodes <- getNodeSet(language,"//cm") lang.titles = as.character( sapply(lang.nodes, xmlGetAttr, "title") ) unimplemented <- setdiff(PT.titles, lang.titles) unimplemented }
- Usage
find.unimplemented.tasks(lang="Python") langs <- c("R","python","perl") sapply(langs, find.unimplemented.tasks) # fetching data for multiple languages</lang>
Ruby
Finds tasks that are either not implemented or omitted. Sorts by task creation time.
Uses the RosettaCode
module from Count programming examples#Ruby
<lang ruby>require 'rosettacode'
require 'time'
module RosettaCode
def self.get_unimplemented(lang) programming_tasks = [] category_members("Programming_Tasks") {|task| programming_tasks << task}
lang_tasks = [] category_members(lang) {|task| lang_tasks << task}
lang_tasks_omit = [] category_members("#{lang}/Omit") {|task| lang_tasks_omit << task}
[programming_tasks - lang_tasks, lang_tasks_omit] end
def self.created_time(title) url = get_api_url({ "action" => "query", "titles" => title, "format" => "xml", "rvlimit" => 500, "prop" => "revisions", "rvprop" => "timestamp" }) doc = REXML::Document.new open(url) REXML::XPath.each(doc, "//rev").collect do |node| Time.parse( node.attribute("timestamp").value ) end.min end
end
puts Time.now lang = ARGV[0] || "Ruby" unimplemented, omitted = RosettaCode.get_unimplemented(lang) unimplemented.collect {|title| [title, RosettaCode.created_time(title)]} .
sort_by {|e| e[1]} . each do |title, date| puts "%s %6s %s" % [ date.strftime("%Y-%m-%d"), omitted.include?(title) ? "[omit]" : "" , title ] end
</lang>
Output for Ruby
2010-04-05 11:08:07 -0500 2007-01-14 Table creation 2007-01-25 [omit] Pointers and references 2007-02-04 SQL-based authentication 2007-02-09 Metered concurrency 2007-02-27 [omit] Address of a variable 2007-02-27 [omit] Variable size/Set 2007-02-27 Variable size/Get 2007-06-08 OpenGL 2007-06-08 HTTPS/Authenticated 2007-11-06 Pattern matching 2007-11-08 [omit] Parametric polymorphism 2007-11-13 Special characters 2007-12-11 Arithmetic evaluation 2007-12-21 [omit] Proof 2007-12-24 Plot coordinate pairs 2007-12-24 Polynomial regression 2007-12-24 Compare sorting algorithms' performance 2008-03-27 Dragon curve 2008-03-28 Formal power series 2008-09-11 RCRPG 2008-11-02 Active object 2008-11-13 Window creation/X11 2008-12-05 [omit] Constrained genericity 2009-02-17 Rendezvous 2009-03-22 Arena storage pool 2009-05-23 Ray-casting algorithm 2009-05-26 [omit] Memory allocation 2009-05-26 Simulate input/Mouse 2009-05-27 Mouse position 2009-05-27 Keyboard macros 2009-05-27 Window management 2009-05-27 Color of a screen pixel 2009-06-01 HTTPS/Client-authenticated 2009-06-02 Simulate input/Keyboard 2009-06-08 [omit] Create an object at a given address 2009-06-10 Events 2009-06-10 Scope modifiers 2009-08-09 Verify distribution uniformity/Chi-squared test 2009-08-11 Call a function from a foreign language 2009-08-12 Safe addition 2009-12-05 Rate counter 2010-01-02 Loading Animated 3D Data 2010-01-06 Catmull–Clark subdivision surface 2010-01-21 Hough transform 2010-01-25 Compile-time calculation 2010-02-14 Knapsack problem/Bounded 2010-02-21 Deconvolution/1D 2010-02-23 Deconvolution/2D+ 2010-02-24 Knapsack problem/Continuous 2010-03-23 Sutherland-Hodgman polygon clipping 2010-03-23 Find Common Directory Path
Tcl
First, find all members of the Programming_Tasks category, then find all members of the $lang
category. The difference is the list of unimplemented tasks.
This uses the json
and struct::set
packages from
<lang tcl>package require Tcl 8.5 package require http package require json package require struct::set
fconfigure stdout -buffering none
- Initialize a cache of lookups
array set cache {} proc log msg {
#puts -nonewline $msg
}
proc get_tasks {category} {
global cache if {[info exists cache($category)]} {
return $cache($category)
} set base_url http://www.rosettacode.org/w/api.php set query {
action query list categorymembers cmtitle Category:%s format json cmlimit 500
} set query [list {*}$query]; # remove excess whitespace set this_query [dict create {*}[split [format $query $category]]] set tasks [list] while {1} { set url [join [list $base_url [http::formatQuery {*}$this_query]] ?] while 1 { set response [http::geturl $url]
# Process redirects
if {[http::ncode $response] == 301} { set newurl [dict get [http::meta $response] Location] if {[string match http://* $newurl]} { set url $newurl } else { set url [regexp -inline {http://[^/]+} $url] append url $newurl } continue }
# Check for oopsies!
if {
[set s [http::status $response]] ne "ok" || [http::ncode $response] != 200 } then {
error "Oops: url=$url\nstatus=$s\nhttp code=[http::code $response]" } break }
# Get the data out of the message
set data [json::json2dict [http::data $response]] http::cleanup $response # add tasks to list foreach task [dict get $data query categorymembers] { lappend tasks [dict get [dict create {*}$task] title] } if {[catch {
dict get $data query-continue categorymembers cmcontinue } continue_task]} then {
# no more continuations, we're done break } dict set this_query cmcontinue $continue_task } return [set cache($category) $tasks]
}
proc get_unimplemented {lang} {
set tasks [get_tasks Programming_Tasks] set collected [get_tasks Collection_Members] set doneTasks [get_tasks $lang] set omittedTasks [get_tasks $lang/Omit]
# Map generic collection task categories to specific ones set tasks [regsub -all {Category:(\S+)} $tasks "\\1/$lang"]
set collectOfLang [struct::set intersect $collected $doneTasks] set ignorable [struct::set union $doneTasks $omittedTasks $collectOfLang] set unimplemented [struct::set difference $tasks $ignorable]
puts "\n$lang has [llength $unimplemented] unimplemented programming tasks:" if {[llength $unimplemented]} {
puts " [join [lsort $unimplemented] "\n "]"
}
}
foreach lang {Perl Python Ruby Tcl} {
get_unimplemented $lang
}</lang>