blog.visualp.com
이다.
1. Eclipse에서 New/Dynamic Web Project를 생성한다.
2. 프로젝트가 생성되면 Eclipse/Project Explorer에 springbloom 폴더가 생긴다.
4. 프로젝트의 /WebContent/web.xml파일을 수정한다.
5. 프로젝트의 /WebContent/index.jsp 파일을 만든다.
6. project를 build하고 publish한다음, 서버를 실행하여 http://localhost:8080/springbloom을 접속한다.
SCORM content interoperability depends on the ability of SCORM content objects to discover a SCORM API instance provided by the LMS in a related frame of window. Sometimes the discovery algorithm fails in FireFox because of an unexpected side effect of the FireFox scripting security implementation. This can happens if a SCO is launched in a mixed window or frame environment in which the discovery algorithm stumbles on a window with content from another domain. This document describes an improved API discovery scripting technique that prevents this problem without compromising functionality or security.
The basic SCORM API discovery algorithm is well specified in IEEE 1484.11.2 and in the SCORM Runtime Environment book. The same ECMAScript algorithm works for SCORM 2004 and SCORM 1.2, except for the fact that the name of the API object is different. In SCORM 1.2 the object is named "API" and in SCORM 2004 it is named "API_1484_11". In the rest of this document, we will assume SCORM 2004. While there have been proposals for "improvements" to the algorithm as it is implemented in the informative script samples provided in the IEEE standard and the SCORM document, such improvements do not modify the basic algorithm.
The algorithm searches the window context in which the SCO has been launched. If first looks at the parents, if any, of the frame in which the SCO might have been launched. If it does not find the API object there, it looks at the opener of the window in which the SCO has been launched and up its parent chain. This works very well most of the time. However, in some rare and obscure circumstances, the generic script will fail in the FireFox browser.
The conditions under which the generic script fails are
When both conditions are met, the Firefox script fails silently and completely. The FireFox JavaScript console shows an uncaught exception because "Window.API_1484_11" is not allowed. This is not displayed as a typical JavaScript error with a line number. Close inspection of the code shows that this happens when the window that is being inspected displays content from a different domain. Instead of returning null when the existence of a non-existent property of the "foreign" window is checked, FireFox triggers a fatal script exception. While this makes sense as a way to discourage "probing" cross-scripting exploits, it also makes life more difficult for legitimate content objects that can dynamically adapt to different environments.
This is an obscure bug, and one that can be difficult to even recognize or diagnose. The conditions where the search algorithm might encounter a "foreign" window are probably extremely rare in e-Learning environments. But people are showing more interest in using SCORM content in environments that are richer than the traditional CBT and that may gather content and resources from various sources. This might be through embedding in portals or simulations, or by mixing and matching resources in a Web 2.0 "mash-up". Also, SCOs are sometimes designed so that they can be used with or without a LMS, maybe for performance support or demonstration purposes. This FireFox "feature" and its effect on a SCO was actually discovered in the context of such a demonstration. In that demonstration, no LMS was expected. Initialization of some other features of the SCO failed as FireFox stopped script execution while the SCO was attempting to check whether a SCORM API was available. This bug was discovered by inspecting web server logs and wondering why another file which the SCO references in a normal run was never being loaded.
The fix for this problem, at the ECMAScript level, is quite simple but still requires some careful coding to avoid introducing new bugs. Basically, it consists of using a try/catch control structure when testing a window for presence of the API object. This in turn requires adding some complexity to the algorithm, as in the example below.
Consider the following generic discovery script:
var gAPI = null; // Stand-in for the API object, if found. function _ScanForAPI(win) { // This function is called by GetAPI var nFindAPITries = 500; while ((win.API_1484_11 == null)&& (win.parent != null)&&(win.parent != win)) { nFindAPITries--; if (nFindAPITries < 0) return null; win = win.parent; } return win.API_1484_11; } function GetAPI(win) { // Sets gAPI to be a reference to the API object provided by the RTE, // or leave it as null if no API object could be found. // Parameter win is the SCO's window if ((win.parent != null) && (win.parent != win)) { gAPI = _ScanForAPI(win.parent); } if ((gAPI == null) && (win.opener != null)) { gAPI = _ScanForAPI(win.opener); } }
FireFox fails in the _ScanForAPI function when it is asked to evaluate win.API_1484_11 if doing so leads to an uncaught security exception. There is a risk of failure if any of the window.xxx calls touches a "foreign" window. So, the fix involves catching and handling the exception if it occurs, as follows:
var gAPI = null; // Stand-in for the API object, if found. function _ScanForAPI(win) // Revised to handle x-scripting errors { // This function is called by GetAPI var nFindAPITries = 500; // paranoid to prevent runaway var objAPI = null; var bOK = true; var wndParent = null; while ((!objAPI)&&(bOK)&&(nFindAPITries>0)) { nFindAPITries--; try { objAPI = win.API_1484_11; } catch (e) { bOK = false; } if ((!objAPI)&&(bOK)) { try { wndParent = win.parent; } catch (e) { bOK = false; } if ((!bOK)||(!wndParent)||(wndParent==win)) { break; } win = wndParent; } } return objAPI; } function GetAPI(win) // Revised to handle x-scripting errors { // Sets gAPI to be a reference to the API object provided by the RTE, // or leave it as null if no API object could be found. // Parameter win is the SCO's window var wndParent = null; var wndOpener = null; try { wndParent = win.parent; } catch(e) { } try { wndOpener = win.opener; } catch(e) { } if ((wndParent != null) && (wndParent != win)) { gAPI = _ScanForAPI(wndParent); } if ((gAPI == null) && (wndOpener != null)) { gAPI = _ScanForAPI(wndOpener); } }
And that is all there is to it. For SCORM 1.2, just substitute "API" for "API_1484_11".
Design notes: The structure of the new functions is obviously more complex, to ensure a clean break in case an exception gets triggered by cross-scripting restrictions when a "foreign" window is inspected. I considered replacing "(win.API_1484_11)" in the original function with a call to a function that would do the testing with try/catch, e.g. something like "(testForAPI(win))" but then I realized that for all we know FireFox might also add an uncaught exception for "(win.parent)" even if it does not seem to do it now. The revision above does not depend on another function, and it never encounters the "win.parent" situation even if it were to become invalid, because it stops testing the window as soon as an error is detected in "win.API_1484_11". This is "defensive" scripting.
This solution does impose some constraints. However those constraints should not be an issue for most deployments.
If it is not possible to fix up the SCOs or to use up to date browsers, the infrastructure-level workaround is always available. It consists of drawing the SCORM content, the LMS and any other content used in the same browser context from the same server, or rather from what appears to the browser as being a single server, even if they actually come from different origin servers. This is typically done through the use of a reverse proxy.
Where it is not possible to fix up existing SCOs, another workaround is through the use of "wrapper SCO" that plays the SCO in a frame, and that contains a relay API object that is initialized by an error-handling discovery script. The actual SCO's discovery script will find this relay API first and stop there, never causing an error.
This is an obscure bug that has the potential for causing various levels of grief and mysterious failures. I would recommend to not worry overly about it when dealing with existing content unless the bug already causes problem. However, new content should use an updated, defensive discovery scripting approach to prevent uncaught script exceptions.
This scripting strategy allows a SCO to run anywhere without risk that the initialization scripts will be rudely stopped. Even if the script is stopped silently, there is usually more initialization to be done after discovering whether or not an API is available.
Loading external data of any kind in to Flash is never instantaneous, therefore it usually gives rise to the need for some sort of checking process - usually in the form of a preloader.
The MovieClipLoader API (Applications Programming Interface) takes away much of the necessary work involved in loading images and swfs in to our Flash movies, and allows us to be notified about the various stages of loading, ultimately giving us more control over our movie, and helping us cut down on the amount of code we need to write.
We can use a single instance of the MovieClipLoader class to load one or more files in to a single movieclip/level, or create a different MCL instance for each file we load.
I have decided to split the subject up in to two seperate tutorials. The first will introduce you to basic MCL usage, and the second will show you how to use a single MovieClipLoader instance to load content in to multiple (duplicated) movie clips, and will employ the use of a listener object. It is possible to use MCL without the need for a listener, and as some of you will not be familiar with how they work you may find it easier to learn about the MovieClipLoader if we ignore using a listener for the time being.
With that said, let's look at what makes the MovieClipLoader class so useful - callback functions. Callbacks are the 'internal organs' of tha MCL class - they are what provide us with the information on the status of the files being downloaded. There are 7 callbacks in all, 5 of them give us infomation about various stages of the loading process. The other two deal with unloading and errors. Let's take a very brief look at them before we proceed:
MovieClipLoader callbacks:
The list of callback functions and short explanations, though brief, should be pretty self-explanatory, and the best way to learn about the MovieClipLoader class is to jump straight in and get our hands dirty, but before we do there are a couple of things to note.
Firstly, MCL is new to Flash 7, so ensure that Flash is set to export swfs as Flash 7 and using AS2 - the settings for both of these can be found under the FILE->PUBLISH SETTINGS menu. The second important thing to note is that for our MovieClipLoader to function properly we'll need to view it through a browser. If you try and test it directly through Flash your bytesLoaded and bytesTotal values will end up being recorded as zero.
In our example we're going to use a single MovieClipLoader object to load several pictures in to empty movieclips. The swfs and images needed for this example can be found in the sourcefile for this tutorial and can be seen in action here.
Building the Example:
1. Create a new movie (.fla) and put the following code on the first frame of the root timeline:
_root.traceBox.vScrollPolicy ="on";
function myTrace(msg)
{
_root.traceBox.text += msg + newline;
_root.traceBox.vPosition = _root.traceBox.maxVPosition;
}
All we're doing here is setting up a basic trace function, the output of which will be displayed in the TextArea component that we are about to place on the stage. _root.traceBox.vPosition = _root.traceBox.maxVPosition keeps the scrollbar moving as more content is added, so that we can see new traces as they appear without the need to manually scroll. vScrollPolicy makes sure the vertical scrollbar is on at all times.
2. Now drag an instance of the TextArea component on stage from your components panel, resize it to make it big enough to display our traces properly and give it an instance name of "traceBox".
3. The next step is to create a new movieclip symbol, and place 3 instances of that symbol on the main stage, giving them the instance names of "myMC1", "myMC2" and "myMC3". We will load our images and swfs in to these, so space them about at 200 pixels apart. Our loaded images will actually be much bigger than 200 pixels wide, but we'll resize them once they've downloaded. It is not good practice to make your images larger than the final size at which they will be displayed of course, but for the sake of this tutorial it will allow us to see the onLoadInit() method in action.
4. The next thing to do is to create our new MovieClipLoader object which we'll call myMCL, so add the following code to the first frame, below our trace function:
var myMCL = new MovieClipLoader();//create an instance of MovieClipLoader
myMCL.onLoadStart = function (targetMC)
{
var loadProgress = myMCL.getProgress(targetMC);
myTrace ("The movieclip " + targetMC + " has started loading");
myTrace("Bytes loaded at start=" + loadProgress.bytesLoaded);
myTrace("Total bytes loaded at start=" + loadProgress.bytesTotal);
}
6. We have already assigned functionality to our onLoadStart() method. Now we will work through the remaining methods that I listed earlier, and see how we assign functionality to those too. Next up is onLoadProgress() which accepts three arguments (the movieclip in question and its byte-loaded details). Again, we send those details to be displayed in our trace function. Add the following code to frame 1:
myMCL.onLoadProgress = function (targetMC, loadedBytes, totalBytes) {
myTrace ("movie clip: " + targetMC);
myTrace("Bytes loaded at progress callback=" + loadedBytes);
myTrace("Bytes total at progress callback=" + totalBytes);
}
myMCL.onLoadComplete = function (targetMC)
{
var loadProgress = myMCL.getProgress(targetMC);
myTrace (targetMC + " has finished loading.");
myTrace("Bytes loaded at end=" + loadProgress.bytesLoaded);
myTrace("Bytes total at end=" + loadProgress.bytesTotal);
}
myMCL.onLoadInit = function (targetMC)
{
myTrace ("Movie clip:" + targetMC + " is now initialized");
targetMC._width = 170;
targetMC._height = 170;
}
myMCL.onLoadError = function (targetMC, errorCode)
{
myTrace ("ERRORCODE:" + errorCode);
myTrace (targetMC + "Failed to load its content");
}
//load the files in to their respective targets
myMCL.loadClip("http://www.yourdomain.com/test1.swf","_root.myMC1");
myMCL.loadClip("http://www.yourdomain.com/test2.swf ", "_root.myMC2");
myMCL.loadClip("http://www.yourdomain.com/pic.jpg", "_level0.myMC3");
//load the files in to their respective targets
myMCL.loadClip("test1.swf","myMC1");
If all went well it should look something like my example. If not you can always download the MCL_tutorial.zip and compare the two fla's to see where they differ.
Remember, for everything to work properly you need to be testing throuhg a browser (and preferably on line so you can see the files loading in real time). You also need to be exporting your code as ActionScript 2.
In the second part of this tutorial I'm going to show you how to use the MovieClipLoader class in a real-world situation, in order to solve a common problem when assigning event handlers to MovieClips dynamically.
The second tutorial makes use of a listener object, so it will help if you have a basic understanding of listeners and what they do. If you haven't used listeners before then I can give no stronger recommendation then to read Senocular's excellent tutorial (as are all his tutes by the way) which can be found here.
Completing the second tutorial should solidify all the things we covered here. Have a rest, make yourself a coffee and then if you're ready you can continue... (See the link to Part 2 of this tutorial, at the bottom of this page)
This tutorial is ideally used in addition to my "CSS in Flash" tutorial and covers topics such as loading external XML-formatted text into Flash and using external CSS to display that text within the TextArea component. These are questions I've been seeing on the forums of late, and so I hope it will answer some of your questions.
First off, we're going to create some XML formatted data to bring in to our movie. Open up your favourite text editor and paste the follow text in to it:
<drunken>This is some drunken text</drunken>
<monkey>This is some monkey text</monkey>
<snake>This is some snake text</snake>
<dragon>This is some dragon text</dragon>
Our file above will work, but it's standard practice to enclose all our same-level tags (nodes) in a single root node, and so that's what we'll do. Amend the above code to look like this:
<kungfu>
<drunken>This is some drunken text</drunken>
<monkey>This is some monkey text</monkey>
<snake>This is some snake text</snake>
<dragon>This is some dragon text</dragon>
</kungfu>
With that out of the way we'll create our flash movie. Open a new movie (.fla) and drag an instance of the TextArea component from the components panel on to the main stage, resize it to about 200*300 pixels and give it an instance name of "myText". By default the wordwrap property should be set to true, whilst the html and multiline properies should be set to false. We'll use code to ensure that all Boolean values are set to be true. We are also going to set condenseWhite to be true. This is explained in detail on the following page. Paste this code in to frame1 of your main timeline:
//init TextArea component
myText.html = true;
myText.wordWrap = true;
myText.multiline = true;
myText.label.condenseWhite=true;
//load css
kungFuStyle = new TextField.StyleSheet();
kungFuStyle.load("kungfu.css");
myText.styleSheet = kungFuStyle;
We haven't created our stylesheet yet, and I want to demonstrate a few things before we do, so for the time being we're going to comment out the code we just wrote, and make it inoperable. To comment out a block of code we can surround it with /* and */ so for the time being this is what we'll do. Our stylesheet code should now look like this:
/*kungFuStyle = new TextField.StyleSheet();
kungFuStyle.load("kungfu.css");
myText.styleSheet = kungFuStyle;*/
We've already created our XML though, and so the next step is to load it into the TextArea component which is what we'll do next. The code we require is below. Add it to frame one and then we'll take a quick look at what it does.
//load in XML
kungFuContent = new XML();
kungFuContent.ignoreWhite = true;
kungFuContent.load("kungfu.xml");
kungFuContent.onLoad = function(success)
{
if(success)
{
myText.text = kungFuContent;
}
}
Save your fla in the same location as kungfu.xml and test your movie.
If all has gone well you should see something like this:
Now is a good time to talk about ignoreWhite and also the condenseWhite property which I alluded to earlier.
ignoreWhite excludes all white-space (linebreaks, carriage-returns, non-breaking spaces) from our XML when it is brought in to Flash (ie parsed). However, it is only the white-space inbetween the nodes, and nodes that contain nothing but white-space that are ignored. Any white-space withina text node, including leading or trailing whitespace, is preserved. You can see this for yourself by opening up the kungfu.xml file, and inserting a carriage-return (ie press the enter/return key) directly after an opening tag such as <snake>. Now save your ammended XML file and test the fla. When you test it you can see that the whitespace is included.
There is however a solution to this potential formatting problem. You can use condenseWhite to get rid of that unwanted whitespace within the node. For a TextField use: TextField_Instance.condenseWhite=true; and for a TextArea use: TextArea_Instance.label.condenseWhite=true;.
Many thanks to Christopher Watts and Rob Verhoef for the info and solution here =)
Okay, so our example isn't very useful at the moment. Our text is all bunched up. Now is a good time to create our CSS file and apply it to the TextArea.
I covered CSS to a reasonable level in my last tutorial, but there was one thing I omitted, and that was defining new tags. Last time when we created our styles we used predefined tags with 'classes'. We preceded our class names with a period, such as ".alert" and then we use them in conjunction with predefined tags such as span like this: <span class='alert'>some text</span>
To create a new tag we simply leave out the period. In the following CSS we will use a mixture of newly defined tags with names that correspond to our XML nodes, and throw in a few classes just to spice things up a little, so open up your favourite text editor and paste this style sheet into it.
drunken {
color: #FF0000;
font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
font-size: 18px;
font-weight: bold;
display: inline;
}
monkey {
color: #0000FF;
font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
font-size: 10px;
font-weight: normal;
display: inline;
}
.snake {
color: #00FF00;
font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
font-size: 12px;
font-weight: bold;
display: inline;
}
Our stylesheet code is still commented out, so remove the comments from the beginning and end of the code block in the first frame of the fla and test the movie. With any luck it should look something like this:
Okay, it's looking a little better now but not perfect because the text is still bunched up. What's going on? It's due to this line in our css: display: inline;. Without it Flash defaults to "display: block", so I just wanted to show you the difference and make you aware of what it does. You may also have noticed that the "snake" text wasn't green. This is because our stylesheet defines snake as a class (.snake). Let's remedy one of these things right now. Rather than letting Flash default to "block", we will explicitly set the display properties for "drunken" and "monkey" to read display: block;. Also, let's add another new css definition for "dragon". Paste this code into kungfu.css and save the file:
dragon {
color: #000000;
font-family: Verdana, Geneva, Arial, Helvetica, sans-serif;
font-size: 10px;
font-weight: normal;
display: inline;
}
<kungfu>
<drunken>Although the drunken style moves often
appear harmless, they can be deadly against
even the most skilled opponents.</drunken>
<monkey>Monkey style is deceptive and versatile.
It is generally meant for smaller size persons.</monkey>
<snake>Snake style does not deal in humaneness,
it only deals with delivering
quick, maiming or killing strikes.</snake>
<dragon>Dragon Style is a highly aggressive kung fu style,
relentlessly pressing against the opponent with
an unremitting chain of attack.</dragon>
</kungfu>
That's better. Just a one more tweak and then we're done (I was planning to cover adding images to text fields in this tutorial but I think that will have to wait for another day). Our final tweak is to the xml document, so open it up and change the "snake" tags to this:
<span class='snake'>Snake style does not deal in humaneness,
it only deals with delivering quick, maiming or killing strikes.</span>
Our text about the snake style is now green, as specified by the snake class.
However, you should also note that the following text about "dragon" style is on the same line.
Your first thought will probably be that we need to change display: inline; to display: block;, but actually that doesn't appear to be the problem in this case; and nor does it appear to be connected with the order in which our newly defined tags and snake-class appear in our kungfu.css file
Whilst you may expect display: inline; to force a break, <span> is not designed to be a 'breaking' tag like the <div> or <p> tags and the result is that your content will not begin on a new line. You can swap the span tag for a paragraph tag if you do want to 'force' the new line, or alternatively don't use a class in situations like this, but instead use a newly created tag (ie as demonstrated with other tags in this tutorial such as "drunken" and "monkey")
Well, that's all for this tutorial. I'd like to thank Tom Schreck for his suggestions regarding the tag-break problem. I hope this tute has answered some of the questions I'm hearing on the forums.
import java.io.*; public class Person implements Serializable { public String firstName; public String lastName; private String password; transient Thread worker; public Person(String firstName, String lastName, String password) { this.firstName = firstName; this.lastName = lastName; this.password = password; } public String toString() { return new String(lastName + ", " + firstName); } } class WritePerson { public static void main(String [] args) { Person p = new Person("Fred", "Wesley", "cantguessthis"); ObjectOutputStream oos = null; try { oos = new ObjectOutputStream(new FileOutputStream("Person.ser")); oos.writeObject(p); } catch (Exception e) { e.printStackTrace(); } finally { if (oos != null) { try {oos.flush();} catch (IOException ioe) {} try {oos.close();} catch (IOException ioe) {} } } } } class ReadPerson { public static void main(String [] args) { ObjectInputStream ois = null; try { ois = new ObjectInputStream(new FileInputStream("Person.ser")); Object o = ois.readObject(); System.out.println("Read object " + o); } catch (Exception e) { e.printStackTrace(); } finally { if (ois != null) { try {ois.close();} catch (IOException ioe) {} } } } }
Read object Wesley, Fred
public class Person implements Serializable { public String firstName; public String lastName; int age; private String password; transient Thread worker; public Person(String firstName, String lastName, String password, int age) { this.firstName = firstName; this.lastName = lastName; this.password = password; this.age = age; } public String toString() { return new String(lastName + ", " + firstName + " age " + age); } } class WritePerson { public static void main(String [] args) { Person p = new Person("Fred", "Wesley", "cantguessthis", 31); // 이후는 원본과 같습니다.
static final long serialVersionUID = /* some long integer */;
static final long serialVersionUID = 4070409649129120458L;
private void writeObject(ObjectOutputStream stream) throws IOException; private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException;
import java.io.*; public class Person implements Serializable { public String firstName; public String lastName; int age; private String password; transient Thread worker; static final long serialVersionUID = 4070409649129120458L; //이것은 제대로 된 기호화 연산이 아니지만, 실행은 됩니다. //하지만 조금 더 나은 것으로 대신해야 할 것입니다. static String crypt(String input, int offset) { StringBuffer sb = new StringBuffer(); for (int n=0; n<input.length(); n++) { sb.append((char)(offset+input.charAt(n))); } return sb.toString(); } // 실제 응용프로그램에서는 패스워드로의 액세스를 동조하도록 하면서 // 페스워드를 System.out 로 출력해서는 안됩니다! private void writeObject(ObjectOutputStream stream) throws IOException { password = crypt(password, 3); System.out.println("Password encyrpted as " + password); stream.defaultWriteObject(); password = crypt(password, -3); } private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); password = crypt(password, -3); System.out.println("Password decrypted to " + password); } public Person(String firstName, String lastName, String password, int age) { this.firstName = firstName; this.lastName = lastName; this.password = password; this.age = age; } public String toString() { return new String(lastName + ", " + firstName + " age " + age); } }
import java.io.*; public class Person implements Serializable { public String fullName; int age; private String password; transient Thread worker; static final long serialVersionUID = 4070409649129120458L; //이것은 제대로 된 기호화 연산이 아니지만, 실행은 됩니다. //하지만 조금 더 나은 것으로 대신해야 할 것입니다. static String crypt(String input, int offset) { StringBuffer sb = new StringBuffer(); for (int n=0; n<input.length(); n++) { sb.append((char)(offset+input.charAt(n))); } return sb.toString(); } // 실제 응용프로그램에서는 패스워드로의 액세스를 동조하도록 하면서 // 페스워드를 System.out 로 출력해서는 안됩니다! private void writeObject(ObjectOutputStream stream) throws IOException { password = crypt(password, 3); System.out.println("Password encyrpted as " + password); stream.defaultWriteObject(); password = crypt(password, -3); } private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); password = crypt(password, -3); System.out.println("Password decrypted to " + password); } public Person(String firstName, String lastName, String password, int age) { this.fullName = lastName + ", " + firstName; this.password = password; this.age = age; } public String toString() { return new String(fullName + " age " + age); } }
// readObject를 여기의 새 버젼으로 교체하십시오. private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { ObjectInputStream.GetField gf = ois.readFields(); // 새로운 버젼을 가지고 있기를 바라며.... fullName = (String) gf.get("fullName", null); if (fullName == null) { // 이런. 구버젼입니다. fullName을 만들어냅니다. String lastName = (String) gf.get("lastName", null); String firstName = (String) gf.get("firstName", null); fullName = lastName + ", " + firstName; } age = gf.get("age", 0); password = (String) gf.get("password", null); password = crypt(password, -3); System.out.println("Password decrypted to " + password); }
데이터 베이스 시간에 발표한 ER-WIN 사용 법에 대한 자료
[출처]를 반드시 유지 해야 함..
Here are the elements used for SCORM 2004 S&N. These elements go in the imsmanifest.xml file.
The SCORM 2004 books are all PDF files. Personally I am not a fan of PDFs so here is an overview pulled from SCORM_CAM.pdf. In addition google may be able to index this blog post a little better than the PDF.
The main element used for sequencing in the imsmanifest is the <sequencing> element.
The <sequencing> element will usually appear as a child of your <item> elements. (If you didn’t already know, the <item> elements can also be thought of as the Learning Activities.) There should be zero or one <sequencing> element per <item> element.
Here are a couple of excerpts from SCORM_CAM.pdf.
“Sequencing information is associated with items in a hierarchical structure by associating a single <sequencing> element with the hierarchical item. In the context of IMS Content Packages, this is done by including the <sequencing> element within either an <item> element or an <organization> element. “
“Multiplicity: Occurs 1 or More times within the <sequencingCollection> element, if the <sequencingCollection> element is present. Occurs 0 or 1 time for each <item> or <organization> within an IMS content package.”
The children elements of the <sequencing> element are:
<controlMode>
Optional, “parent” element, can be used zero or one time. This element is “the container for the sequencing control mode information including descriptions of the types of sequencing behaviors specified for an activity. This element captures information dealing with the types of sequencing requests that are permitted.”
Attributes:
choice (optional, default value = true)
choiceExit (optional, default value = true)
flow (optional, default value = false)
forwardOnly (optional, default value = false)
useCurrentAttemptObjectiveInfo (optional, default value = true)
useCurrentAttemptProgressInfo (optional, default value = true)
<sequencingRules> ***
Optional, “parent” element, can be used zero or more times. This element is “the container for a sequencing rule description. Each rule describes the sequencing behavior for an activity. Each activity may have an unlimited number of sequencing rules and within any grouping the rules are evaluated in the order in which they are listed.”
Children:
<preConditionRule>
<exitConditionRule>
<postConditionRule>
<limitConditions>
Optional, “parent” element, can be used zero or one time. The ADL recommends this element be used with caution! “ADL supports the usage of only two current limit conditions. The limit condition deals with attempts on the activity and maximum time allowed in the attempt.”
Attributes:
attemptLimit (optional, default value = 0)
attemptAbsoluteDurationLimit (optional, default value = 0.0)
<auxiliaryResources>
The ADL recommends this element be used with caution! There is no additional information for this element.
<rollupRules> ***
Optional, “parent” element, can be used zero or one time. This element is “the container for the set of rollup rules defined for the activity.”
Attributes:
rollupObjectiveSatisfied (optional, default value = true)
rollupProgressCompletion (optional, default value = true)
objectiveMeasureWeight(optional, default value = 1.0000)
Elements:
<rollupRule>
<objectives> ***
Optional, “parent” element, can be used zero or one time. “Optional element, can be used zero or more times. This is a parent element. ”
Elements:
<primaryObjective>
<objective>
<randomizationControls>
Optional, “parent” element, can be used zero or one time. This element is “the container for the descriptions of how children of an activity should be ordered during the sequence process.”
Attributes:
randomizationTiming (optional, default = never)
selectCount (optional, default value = 0)
reorderChildren (optional, default value = false)
selectionTiming (optional, default = never)
<deliveryControls>
Optional, “parent” element, can be used zero or one time. This element is “is the container for the descriptions of how children of an activity should be ordered during the sequence process.”
Attributes:
tracked (optional, default value = true)
completionSetByContent (optional, default value = false)
objectiveSetByContent (optional, default value = false)
<adlseq:constrainedChoiceConsiderations>
Optional, “parent” element, can be used zero or one time. This element is “the container for the descriptions of how choice navigation requests should be constrained during the sequencing process. The constrained choice only applies to the activity for which it is defined.”
Attributes:
preventActivation (optional, default value = false)
constrainChoice (optional, default value = false)
<adlseq:rollupConsiderations>
Optional, “parent” element, can be used zero or one time. This element is “the container for the descriptions of when an activity should be included in the rollup process.”
Attributes:
requiredForSatisfied (optional, default value = always)
requiredForNotSatisfied (optional, default value = always)
requiredForCompleted (optional, default value = always)
requiredForIncomplete (optional, default value = always)
measureSatisfactionIfActive (optional, default value = false)