tag:blogger.com,1999:blog-38099850694419237452024-02-19T20:12:09.434-10:00Shaoxuan's Engineering LogShaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.comBlogger77125tag:blogger.com,1999:blog-3809985069441923745.post-32819622879707353332010-04-21T16:13:00.004-10:002010-04-21T16:42:28.350-10:00PHP script for SSH access<blockquote></blockquote>Today when I was struggling of slowly FTPing a PHP web application (Magento), which the FTP client estimates will take up to 4 hours for that 50+M of files, I start wondering if there is other way to FTP the package to server then unpack it there, not only for dev team, but also for customers. But we have only FTP access to the server, no SSH available, not if I login directly with root certification. After some discuss with colleagues, we can up of an idea of writing PHP code using the <a href="http://php.net/manual/en/function.exec.php">exec</a> command to execute the unpack command. This sounds too simple and dangers, and what's worse, it works in our servers. Then I took a little additional effort to wrap up a relatively nicer PHP page to pretend SSH access from browser.<div><br /></div><div>The code is <a href="https://docs.google.com/uc?id=0B3Taisq6_NSVN2U2NTBjNTktYmJlMC00YzM3LWE0NjgtM2EwODBkNmY4NmVl&export=download&hl=en">here</a>.</div><div><br /></div><div>It is easy to see how dangers this could be in shared web hosting. It is even worse when the php is executed as the same user, like 'apache', because that means a client could get full access to others files, and can screw big things up.</div>Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com1tag:blogger.com,1999:blog-3809985069441923745.post-12154574789194986432010-04-02T09:25:00.002-10:002010-04-02T09:37:34.628-10:00Wasted an hour to fix "$(".datepicker").datepicker is not a function"I have been using datepicker in the <a href="http://jqueryui.com/">jQuery UI</a> package for quite a while and it was always nice and easy, until this morning when I was trying to add it to a page, it keep giving me the error "$(".datepicker").datepicker is not a function". I check from firbugs that, the jquery-ui-1.7.2.min.js is included, so as the jquery-1.3.2.min.js. I was copying the code from another page I wrote, where the datepicker works just well. I was haunting around that several lines of code, trying to use other version of jQuery and jQuery UI, but found nothing, until I roll down to the page and saw that there is another script reference of jquery-1.3.2.min.js, which I added 2 days ago for other purpose. As soon as I remove that second include, the datapicker come back to life.<br /><br />The lesson is clear, yet is not frequently mentioned and would be a headless blocker for javascript newbies like me. Include the jQuery core library again will overwrite the functions added by the jQuery UI, thus the functions are missed in the final js object.<br /><br />It is not a good practice to include these kind of library in the middle of a page. But it may still happen some where by some reasons. If you get weird javascript function not found error, try to look for these duplicated library include.Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com7tag:blogger.com,1999:blog-3809985069441923745.post-19598538924904929732009-11-10T20:24:00.003-10:002009-11-10T20:41:54.877-10:00Use SearchControl and SearchForm of Google Search Ajax APIWhen using the <a href="http://code.google.com/apis/ajaxsearch/documentation/">Google Search Ajax API</a>, we may sometimes what to add functions when user initiate a search or clear the search result. the <a href="http://code.google.com/apis/ajaxsearch/documentation/reference.html#_class_GSearchForm">SearchForm</a> is designed to do this. It provides <code>.setOnSubmitCallback(object, method)</code> and<code> .setOnClearCallback(object, method)</code> to let developer define method to call when user search or clear search result. But can we use the SearchControl, which provides easy-to-use and nice wrapped searcher, along with the SearchForm? The answer is yes. Here is the example code of using them together.<br /><blockquote>function OnLoad() {<br /> var searchControl = new google.search.SearchControl();<br /> searchControl.addSearcher(new google.search.WebSearch());<br /> searchControl.addSearcher(new google.search.ImageSearch());<br /><br /> var drawOptions = new google.search.DrawOptions();<br />drawOptions.setDrawMode(google.search.SearchControl.DRAW_MODE_TABBED);<br /> drawOptions.setSearchFormRoot(document.getElementById<br /> ("searchcontrol"));<br /> searchControl.draw(document.getElementById("containerResults"), drawOptions);<br /> <br /> var searchForm = new google.search.SearchForm(true, document<br /> .getElementById('searchcontrol'));<br /> searchForm.setOnSubmitCallback(searchControl, function() {<br /> this.execute(searchForm.input.value);<br /> });<br /> searchForm.setOnClearCallback(searchControl, function() {<br /> searchForm.input.value = '';<br /> searchControl.clearAllResults();<br /> });<br /> searchForm.execute(QueryString);<br />}<br />google.setOnLoadCallback(OnLoad);</blockquote><br />The HTML code is<br /><br /> < id="searchcontrol"><br /> < id="containerResults"><br /><br />The point to collect this two part together is <span style="font-style: italic;">drawOptions.setSearchFormRoot(document.getElementById("searchcontrol"));</span>, which tells the SearchControl where to look for the associated SearchForm. Another thing to notice is that, in the SearchForm.SetOnCallBack, the execute() method to call should be the one of the SearchForm, like <span style="font-style: italic;">this.execute(searchForm.input.value);</span>, not the one of the SearchControl (<span style="font-style: italic;">searchControl.execute(searchForm.input.value);</span>), otherwise, the method set to OnClearCallBack will not be called when user clear search result.Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com0tag:blogger.com,1999:blog-3809985069441923745.post-25958734669802756172009-11-10T20:03:00.005-10:002009-11-10T20:42:42.728-10:00Things to notice when testing form on Wicket<a href="http://wicket.apache.org/">Wicket</a>, a Java-based web application framework, provides powerful tester to test the application. The tester can simulate activities of users on the web application. The form tester is a component of the tester, which use to test form behavior on the page. However, there are something one need to notice when using the form tester.<br /><br />Let's look at this example.<br />We test a form in the Checkout page, which looks like this<br /> <form id="form"><table><br /> <tbody><tr><br /> <th>Name</th><br /> <td><input id="name" type="text"></td><br /> </tr><br /> <tr><br /> <th>Street</th><br /> <td><input id="street" type="text"></td><br /> </tr><br /> <tr><br /> <th>Zip code</th><br /> <td><input id="zipcode" type="text"></td><br /> </tr><br /> <tr><br /> <th>City</th><br /> <td><input id="city" type="text"></td><br /> </tr><br /> <tr id="state-wmc"><br /> <th>State</th><br /> <td><br /> <select id="state"> <option>Alabama</option> <option>Nebraska</option> </select><br /> </td><br /> </tr><br /> <tr><br /> <th><br /></th><br /> <td><br /> <input id="cancel" value="Cancel" type="button"><br /> <input id="order" value="Order!" type="submit"><br /> </td><br /> </tr><br /></tbody></table></form>The test code is<span class="ul-threaded" style="margin: 1em 0pt 0pt -20px;"><span class="text-cell"><br /><blockquote style="font-style: italic;">FormTester formTester = tester.newFormTester("form");<br />formTester.setValue("name", "Philip");<br />formTester.setValue("street", "Main Street");<br />formTester.setValue("zipcode", "96822");<br />formTester.setValue("city", "Anchorage");<br />formTester.setValue("state-wmc:state", "Alaska");<br />formTester.submit();<br />tester.assertRenderedPage(Index.class);</blockquote><br /></span></span>But when run the test, the last assertion indicate that it still in the Checkout page. Did you find anything wrong? The problem lies in<br /><blockquote style="font-style: italic;"><span class="ul-threaded" style="margin: 1em 0pt 0pt -20px;"><span class="text-cell">formTester.setValue("state-wmc:state", "Alaska");</span></span></blockquote><span class="ul-threaded" style="margin: 1em 0pt 0pt -20px;"><span class="text-cell"><br />And the fix is</span></span><blockquote><span class="ul-threaded" style="margin: 1em 0pt 0pt -20px;"><span class="text-cell"><br /></span></span><span class="ul-threaded" style="margin: 1em 0pt 0pt -20px;"><span class="text-cell"><span style="font-style: italic;">formTester.select("state-wmc:state", 1);</span> </span></span></blockquote><span class="ul-threaded" style="margin: 1em 0pt 0pt -20px;"><span class="text-cell"></span></span><br /><span class="ul-threaded" style="margin: 1em 0pt 0pt -20px;"><span class="text-cell"><br />The reason is that, FormTester.setValue() method cannot be used to set the value of selection field, thus the <span style="font-style: italic;">"state-wmc:state"</span> field is not filled, so when the form is submitted, an error of invalid value occurs. This is an usual mistake when using FormTester.<br /><br />Additionally, in order to find out what goes wrong when the test fail, we can use the Tester.assertErrorMessages(String[]) to see the error message.<br /></span></span>Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com0tag:blogger.com,1999:blog-3809985069441923745.post-29798073469454418852009-08-24T13:03:00.004-10:002009-11-10T20:42:56.268-10:00Final Summary of GSoC 2009As the fall semester 2009 begins, the GSoC 2009 goes to an end. During it I again successfully complete the project to the excepted goal.<br /><br />At the beginning of the project, problems of the Issue sensor and its data structure design draw me quite back from the original schedule. However, after I settle it down, the further process become amazingly smooth. It took me like 2~3 weeks to finish Issue DailyProjectData analysis, and another week for Telemetry, and, several minutes to put it into Software ICU! I again experience how a well designed extensible system can boost new developments upon it. Though I am the main developer of the Software ICU, I really have not much to do in previous development of DPD and Telemetry, so it is not my previous experience lead to the boost development.<br /><br />To add Issue analysis to Software ICU only involves editing a single configuration XML file(I was adding to the default configuration, but it is OK to add to your own configuration, if the developer did not upgrade the code in time =P). The main thing to newcomer may be to find out which file to edit and where it is. I just found that there is no documentation about it on hackystat-ui-wicket. I will add it in soon. Another maybe issue is that, none of the current stream classifier looks to fit the conception of Issue analysis. On the other hand, I do not yet have clear idea of how the Issue stream should be indicate the performance of developers. This can be one of the future study of Issue analysis.<br /><br />In conclusion, last year, I followed the path of extensible system design to build the system. This year, I experience the benefit of building a system that way, and I am so thankful that we have done it that way. I am pretty sure this will be the way I keep following from now.Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com0tag:blogger.com,1999:blog-3809985069441923745.post-22674934977223673492009-08-10T22:58:00.002-10:002009-08-10T23:12:28.804-10:00Almost done in summer projectTill today, Telemetry analysis of Issue, and the Issue DailyProjectData page in Project Browser is finished. As the way Telemetry service and Telemetry page in Project Browser implement, the new issue telemetry chart will just show in Project Browser and no modify needed. That means most of expected feature of summer project is done. Only thing not yet finish is put Issue analysis into Software ICU.<br /><br />What I need to do now most is to put Issue sensor in use in Hackystat's hudson service, so that daily issue data will be collected. When Issue Telemetry analysis available, Software ICU can easily utilize it by modifying the configuration xml file.<br /><br />We are in good shape here.Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com0tag:blogger.com,1999:blog-3809985069441923745.post-77531016500560727652009-08-03T21:45:00.003-10:002009-08-03T22:06:20.523-10:00Experiencing TelemetryWork of the past week is on development of hackystat-analysis-telemetry, to include telemetry analysis of Issue data into Hackystat system. Deal to the well constructed system as example and the sufficient documents, it is again quite straight forward to the goal. However, during coding, I found the telemetry language is kind of weird.<br /><br />The language defines Telemetry Charts using some redefined language components, such as Reducers, which generate stream point value from DPD analysis, and axis. In the Chart definition, after define the name and parameters, the kernel part will look like this:<br /><blockquote style="font-style: italic;">chart Issue(member, status) = {<br /> "Issue invocations",<br /> (IssueStream(member, status), yAxisZeroBased("Issue Count"))<br />};</blockquote>Then we need to define the Stream called IssueStream, and after parameter description, the kernel part look like this:<br /><blockquote style="font-style: italic;"><span style="font-size:100%;">streams IssueStream(member, status) = {<br /> "Issue counts for the given mode for this Project",<br /> Issue(member, status)<br />};</span></blockquote><br />The definition of Streams seems redundant to me because it add no additional information to the reducer. So why not using the reducer directly in the Chart definition? I think it will be cooler that the telemetry language can directly use normal reducer like DevTime to generate the member level chart, so that no need to write in Java the member level reducer again.<br /><br />Now I am coding the test cases for the Issue Telemetry analysis, need to make up Issue data again.Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com0tag:blogger.com,1999:blog-3809985069441923745.post-83239606371452562122009-07-27T15:05:00.003-10:002009-07-27T15:13:32.382-10:00Finish milestone to DPDIt is a critical week of the hackystat issue project that the functionalities from issue sensor up to DailyProjectData are ready to release, along with updated documentation found in<br /><a href="http://code.google.com/p/hackystat-sensor-ant/wiki/AntSensorTasksReference#2.13_Issue_Sensor">Ant Task Reference</a><br /><a href="http://code.google.com/p/hackystat/wiki/SensorDataTypeSpecifications?ts=1248740096&updated=SensorDataTypeSpecifications">SensorDataTypeSpecification</a><br /><a href="http://code.google.com/p/hackystat-analysis-dailyprojectdata/wiki/RestApiSpecification?ts=1248743104&updated=RestApiSpecification#3.9_Issue">DPD API</a><br /><br />The new build of Hackystat including these feature should be release very soon. And it will be deployed in our daily hudson build to start gathering issue data.<br /><br />Next setp is to implement Telemetry analysis. Then put all these things into Project Browser, including Software ICU of course.Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com0tag:blogger.com,1999:blog-3809985069441923745.post-50743701613335590132009-07-21T18:56:00.002-10:002009-07-21T19:42:03.760-10:00DPD almost doneIssue analysis for DailyProjectData is almost done. The process is quite straight forward with the existed analyzes as examples. There is nothing interesting to mention in my opinion. It contains a total count of open issue on the dpd data for convenient.<br /><br />When coding for DPD, I actually found some bugs in issue sensor. When testing the sensordata parser, I realize I can makeup some issue instance as CSV for testing. It should be used in tests for issue sensor as well.<br /><br />Just keep working.Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com0tag:blogger.com,1999:blog-3809985069441923745.post-27281097185334040482009-07-14T23:26:00.002-10:002009-07-14T23:44:27.412-10:00Moving step forwardAfter a week's waiting, my little <span class="blsp-spelling-error" id="SPELLING_ERROR_0">MacBook</span> Pro had come back home on Sunday safe and sound, did not lose a single piece of useful data. As soon as I got him back, I start finishing up the issue sensor to ready for commit.<br /><br />After a serious <span class="blsp-spelling-corrected" id="SPELLING_ERROR_1">consideration</span>, I decide to discard the <span class="blsp-spelling-error" id="SPELLING_ERROR_2">RSS</span> feed as data source completely, because firstly it does not provide much more useful information than extract data from issue summary table, secondly the <span class="blsp-spelling-error" id="SPELLING_ERROR_3">RSS</span> feed service seems more unstable than the issue tracking system,which make the sensor unstable as well, and thirdly it make the code more complex and hard to validate data <span class="blsp-spelling-corrected" id="SPELLING_ERROR_4">completeness</span>. My opinion is, if the user really don't want to miss a single update information, just run the sensor as often as he like.<br /><br />I also found it kind of hard to test the issue sensor, because it is almost impossible to have a fully <span class="blsp-spelling-corrected" id="SPELLING_ERROR_5">controllable</span> and repeatable test environment. The content of Google Project Hosting will keep changing. For current state, I test it by run it twice, and make sure the first run generate some issue data, and the second run did not detect any changes. The better way to exam if the sensor working properly is to actually use it. So my job this week is to work on DailyProjectData to use the issue sensordata to generate issue DPD.Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com0tag:blogger.com,1999:blog-3809985069441923745.post-17777261009971572902009-07-06T22:00:00.002-10:002009-07-06T23:00:07.307-10:00Commit Early, Commit OftenI just get a painful lesson of the Commit Early, Commit Often principle. The thing is, my laptop (<span class="blsp-spelling-error" id="SPELLING_ERROR_0">MacBook</span> Pro bought at 07) died on Sunday. I brought it to Apple store and lucky I can get it fix for free, which will take 1 to 2 weeks. However, the code of the new version of issue sensor is still lying on its hard drive, and the data is not guarantee to be undamaged. That means my work for 3 weeks are gone, at least for the coming week or two. In fact, functional code is finished already. I was just waiting for completing the unit tests before commit the code. I am now so regret that I did not commit the code early.Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com0tag:blogger.com,1999:blog-3809985069441923745.post-79274381391616382582009-06-25T20:22:00.002-10:002009-06-25T21:25:07.001-10:00Issue Sensor RedoProgress of issue sensor is behind expectation. After investigated SensorBase's mechanism, I started to redo the issue sensor. At first, I just want to modify the original code somehow to make it a singleton. However, I kind of mess it up and finally almost redo it from scratch. It is almost finish and just need some unit tests before commit the code.<br /><br />The sensor is more difficult than I image, because it now actually do some of the analysis job during sensor data collection. In order to preserve as much information as possible, the sensor take not only RSS feed, but also information from issue tracking system directly. The Google Issue Tracking System provides a RESTful link to the issue summary table in CSV format. This gives information include almost as much everything as extracting from individual issue html page. I only keep the field interesting, they are id, type, status, priority, milestone and owner. Here is how the sensor do its job.<br /><br />Firstly, it retrieve all issue sensor data from sensorbase (It would not be too much because only on piece of data per issue only.), and also get the issue summary table. Then match each issue from the table to a sensordata. If a issue does not have a sensordata for it, it will create a sensordata for it. Secondly, it check the RSS feed, and add update information to the sensor data. The field names, such as id or type, are used as property key, and the property value consists of the field value as well as the timestamp, collected with "--". Finally, new and modified sensor data will be sent to sensorbase.Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com1tag:blogger.com,1999:blog-3809985069441923745.post-29534477719528191792009-06-15T17:25:00.002-10:002009-06-15T18:47:26.437-10:00Cannot put all data search in database<span style="font-weight: bold;">Issue Sensor Data</span><br /><br />The issue sensor data now is decided to use single instance per issue design. The owner of the <span class="blsp-spelling-error" id="SPELLING_ERROR_0">sensordata</span>, which is the major problem of the approach, is set by the issue sensor, before we can come up something better to decide the data owner. We just want to move on to the core part instead of sitting there thinking about the data owner. That is the easiest way, but require most attention of users to ensure things work good, so sufficient documentation may compensate somehow, hopefully.<br /><br /><span style="font-weight: bold;">New <span class="blsp-spelling-error" id="SPELLING_ERROR_1">API</span> to <span class="blsp-spelling-error" id="SPELLING_ERROR_2">SensorBase</span> </span><br /><br />When coding the issue sensor as single instance per issue, it is important to get the data of the given issue efficiently. While the issue is identified by its id (number id usually), and that id is stored as a property in the <span class="blsp-spelling-error" id="SPELLING_ERROR_3">sensordata</span>, it will be nice to extend <span class="blsp-spelling-error" id="SPELLING_ERROR_4">SensorBase's</span> <span class="blsp-spelling-error" id="SPELLING_ERROR_5">API</span> to return <span class="blsp-spelling-error" id="SPELLING_ERROR_6">sensordata</span> which contains a given property with given value. So I start to try to do this. <span class="blsp-spelling-error" id="SPELLING_ERROR_7">Unfortunely</span>, I found it is not easy to accomplish, and should not be include to <span class="blsp-spelling-error" id="SPELLING_ERROR_8">SensorBase's</span> functionality.<br /><br />Firstly I study about the mechanism of its <span class="blsp-spelling-error" id="SPELLING_ERROR_9">API</span>. I thought the <span class="blsp-spelling-error" id="SPELLING_ERROR_10">API</span> will look like http://hostname:port/sensorbase/sensordata/user/timestamp/?sdt=sensordatatype&<span class="blsp-spelling-error" id="SPELLING_ERROR_11">propertyname</span>=<span class="blsp-spelling-error" id="SPELLING_ERROR_12">propertyvalue</span>. It is actually possible to use dynamic property name, by using "{<span class="blsp-spelling-error" id="SPELLING_ERROR_13">propertyname</span>}={<span class="blsp-spelling-error" id="SPELLING_ERROR_14">propertyvalue</span>}" in route definition. Then in the resource, just get the property name and property value as two Strings, just the same way as usual property.<br /><br />Secondly I try to extend the database interface to allow query <span class="blsp-spelling-error" id="SPELLING_ERROR_15">sensordata</span> with given property entry, when I found the current tables in database does not support this query. In the <span class="blsp-spelling-error" id="SPELLING_ERROR_16">sensordata</span> table, the values are (Owner, <span class="blsp-spelling-error" id="SPELLING_ERROR_17">Tstamp</span>, <span class="blsp-spelling-error" id="SPELLING_ERROR_18">Sdt</span>, <span class="blsp-spelling-error" id="SPELLING_ERROR_19">Runtime</span> TIMESTAMP, Tool, Resource, <span class="blsp-spelling-error" id="SPELLING_ERROR_20">XmlSensorData</span>, <span class="blsp-spelling-error" id="SPELLING_ERROR_21">XmlSensorDataRef</span>, <span class="blsp-spelling-error" id="SPELLING_ERROR_22">LastMod</span>), and the property list in stored in the <span class="blsp-spelling-error" id="SPELLING_ERROR_23">XmlSensorData</span>, which is a XML representation of the <span class="blsp-spelling-error" id="SPELLING_ERROR_24">sensordata</span>. In order to get the data, I need to query the <span class="blsp-spelling-error" id="SPELLING_ERROR_25">XmlSensorData</span>. However, in order to get a set of <span class="blsp-spelling-error" id="SPELLING_ERROR_26">XmlSensorData</span>, I need to first get their <span class="blsp-spelling-error" id="SPELLING_ERROR_27">XmlSensorDataRef</span>, then use that to query the <span class="blsp-spelling-error" id="SPELLING_ERROR_28">XmlSensorData</span>(It is not the only way to doing this, but it is the <span class="blsp-spelling-corrected" id="SPELLING_ERROR_29">convention</span> of <span class="blsp-spelling-error" id="SPELLING_ERROR_30">SensorBase</span>, probably to make it easier to separate data instances from query return.). When I get the XML data, I parse the XML and extract the property list, then do the comparison. Then this <span class="blsp-spelling-error" id="SPELLING_ERROR_31">API</span> query will return the <span class="blsp-spelling-error" id="SPELLING_ERROR_32">XmlSensorDataRef</span>. The user actually need to retrieve the data with the data reference again from <span class="blsp-spelling-error" id="SPELLING_ERROR_33">SensorBase</span>. As you can see, there are duplicate query from reference to data instance. That's because the <span class="blsp-spelling-error" id="SPELLING_ERROR_34">SensorBase</span> is trying to do the things that suppose to be done by data user. The most reasonable way is, the user get the data from the data references, then do the comparison to get the data he want by himself.<br /><br />Therefore, the issue sensor will just get all the issue data(with the sensordatatype = issue), then compare the issue id to get the one it need to add data in.Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com0tag:blogger.com,1999:blog-3809985069441923745.post-7659582180419840682009-06-08T22:04:00.002-10:002009-06-08T23:54:16.967-10:00Stuck in Issue Sensordata DesignIssue <span class="blsp-spelling-error" id="SPELLING_ERROR_0">sensordata</span> is so different from other <span class="blsp-spelling-error" id="SPELLING_ERROR_1">sensordata</span> that it does not conceptually belong to a particular user. Instead, it belongs to a software project, but this project is not the same concept of project in <span class="blsp-spelling-error" id="SPELLING_ERROR_2">Hackystat</span> system. In <span class="blsp-spelling-error" id="SPELLING_ERROR_3">Hackystat</span>, a project is just a definition to group up users and data to represent a actual project, however, there does not necessary exist an associated actual project. The problem is, all <span class="blsp-spelling-error" id="SPELLING_ERROR_4">Hackystat</span> <span class="blsp-spelling-error" id="SPELLING_ERROR_5">sensordata</span> belongs to a user. We have to decide a user to <span class="blsp-spelling-corrected" id="SPELLING_ERROR_6">process</span> the data, and that user has to be sure to stay in all the projects which the issue may belong to for the whole life time of the projects. This is like a administrator in the project. But this administrator need to be managed by users, not the system. There is not an administrator defined in Hackystat users, and we dont want to make this exception for just one kind of sensordata(it is not necessary for others).<br /><br />The first design is to store changes of an issue, starts from the creation of the issue, followed by its updates. Then the issue sensordata is assigned to the owner of the update/creation time. The major resource will be the RSS of the issue updates. The good of this is that it keep all the update in the help of RSS, and the owner of the data is reasonable. But the shortage is that the RSS provides limit information. In the creation thread, it only include the comment. In the update threads, it only include the state/labels that being changed. The current unchanged state is unknown from RSS and has to be found out from the issue tracking system(via http in most case). Another problem is when analyse the data, all data started from the project start time have to be gather together to get the view of the given time. It might be a lot computation if there is lots of updates.<br /><br />The second design is to make a single sensordata associated to a single issue. The updates will be store in the properties list of that sensordata, from the same data resource: RSS. In the creation of an issue data, the current state/labels will be extract from issue tracking system, then it is easier to keep track of future changes. Also, it is easier to analyze, only need to go through that single data instance to figure out the state of a given time. However, the problem of this design is the owner of the sensordata, because it has to know the owner to get the data, and in project level analysis, that data owner has to be in the project which the issue should belong to. There is no a reasonable way to answer this question without making some hack or modifying/adding current system definition. It is possible to let user define who the data belongs to, but it is unsave because it require not only the user know excatly what he is doing, but also all sensors collecting data for the same project need to be configure excatly the same. Otherwise, there may exist mutilple copies of the data instance, which is a great fault of the single data assumption.Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com1tag:blogger.com,1999:blog-3809985069441923745.post-7210418121875045792009-05-21T21:00:00.002-10:002009-05-21T21:24:11.840-10:00Summer Plan<span style="font-weight: bold;">Google Summer of Code</span><br />During the summer, I will be doing the Google Summer of Code 2009. My project is to add Issues into Software ICU. The work include from collecting data from issue tracking system to produce end analysis to Software ICU. The data collection part is finished during spring. So the plan for this project is:<br /><ol><li>Review the issue data sensor and install it to <span class="blsp-spelling-error" id="SPELLING_ERROR_0">Hackystat</span> projects<br /></li><li>Write <span class="blsp-spelling-error" id="SPELLING_ERROR_1">DPD</span> analysis for the issue analysis</li><li>Add Telemetry streams about issues</li><li>Add Issues to Software ICU</li><li>Revise the system from head to toe<br /></li></ol>I expect two weeks for the last three tasks. That is 10 weeks. Google Summer of Code last for 14 weeks, so I will have 4 weeks to spare to wherever needed or to catch up in progress if any delay. For the midterm goal, The first two tasks should be finished and the third one should on the half of the way.<br /><br /><span style="font-weight: bold;">Master Thesis</span><br />The thesis is another important task for me this summer, probably the most important one. There are six chapters in my thesis. I might finish each one in one to two weeks. So it will take probably two month to have it done. During this, Philip will revise each chapter for me after I finish it. And I will go over it on the fly. If everything goes as planned, my thesis will be finish before August.<br /><br />The first chapter I will work on is the related work. I am looking for more relative research on empirical engineering to fill up this chapter.Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com0tag:blogger.com,1999:blog-3809985069441923745.post-55180256344549460602009-05-11T23:11:00.003-10:002009-05-12T00:05:08.075-10:00Summary of Spring 09 Semester<span style="font-weight: bold;font-size:130%;" >Brief Summary<br /></span><span style="font-size:130%;"><span style="font-size:100%;"><span style="font-size:100%;"><span style="font-family: georgia;">The most of work relative to my thesis research or Hackystat was done in the first half of this semester. As the semester went on, I began to stuck in the two course I took, </span><a style="font-family: georgia;" href="http://www2.hawaii.edu/%7Enreed/ics606/">ICS606</a><span style="font-family: georgia;"> and </span><a style="font-family: georgia;" href="http://www2.hawaii.edu/%7Esugihara/course/ics621s09/">ICS621</a><span style="font-family: georgia;">. The homework and projects began to accumulate and took me lots of time to accomplish. Thus, my total research and development output is somehow lower than previous semester, and the progress of my thesis is behind my expectation.</span></span><br /><br /></span></span><span style="font-weight: bold;font-size:130%;" >Achievement in Spring 09</span><br /><br /><span style="font-weight: bold;"><span class="blsp-spelling-error" id="SPELLING_ERROR_0">Tech-report</span> of <span class="blsp-spelling-error" id="SPELLING_ERROR_1">Hackystat</span> Classroom <span class="blsp-spelling-corrected" id="SPELLING_ERROR_2">Evaluation</span> in Fall 2008</span><br />In fall 2008, we deploy the <span class="blsp-spelling-error" id="SPELLING_ERROR_3">Hackystat</span> system in class projects of <span class="blsp-spelling-error" id="SPELLING_ERROR_4">ICS</span>413, together with a <span class="blsp-spelling-corrected" id="SPELLING_ERROR_5">questionnaire</span> survey near the end of the semester. Additionally, we gather log data of students' usage of the system. At the beginning of this semester, I started to review the result from the survey and analyze the log data, then wrote a tech-report of this evaluation. While the major component of this evaluation is the Software ICU, most of this tech-report will be able to go into somewhere of my thesis.<br /><br /><span style="font-weight: bold;">Seminar Presentation of Software ICU</span><br />This is one of the most important step in the progress to my thesis. It is a good chance to summarize the system. The slide can be found <a href="http://docs.google.com/Presentation?docid=dht87b9_8f7gc7kd9&hl=en">here</a>. I spent a little more than a week to prepare the presentation. That was quite challenge to me because it was my first time to present to dozens of audiences. But the presentation came out to be a successful one. It really encourage me a lot.<br /><br /><span style="font-weight: bold;"><span class="blsp-spelling-error" id="SPELLING_ERROR_6">Hackystat</span> Manual Sensor</span><br />In Spring 09, my major development contribution to <span class="blsp-spelling-error" id="SPELLING_ERROR_7">Hackystat</span> is the manual sensor, relative posts can be find <a href="http://zsx-engineering-log.blogspot.com/2009/03/more-analysis-on-log-data.html">here</a>, and <a href="http://zsx-engineering-log.blogspot.com/2009/03/self-report-tool-is-ready.html">here</a>. It is a Java Swing application that let user manually input data to reflect their development activities which are not yet have <span class="blsp-spelling-error" id="SPELLING_ERROR_8">Hackystat</span> sensor attached. The current version is just as simple as a plain form plus a raw data viewer.<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">About My Thesis</span></span><br />In the last week, I have setup my plan to graduate in fall 2009. That means, the due day of my thesis will be sometime in the middle of October 2009. But I prefer to finish the stuff earlier, just in case accident happens. My plan is to finish my thesis before Auguest, and then defensive it in early Sepetember.<br /><br /><a href="http://code.google.com/p/csdl-techreports/source/browse/trunk/techreports/09-10/09-10.pdf">Here</a> is the draft of my thesis, which would like to be considered as the technical report for this semester's independent study.Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com0tag:blogger.com,1999:blog-3809985069441923745.post-80657690840805415672009-04-30T14:39:00.002-10:002009-04-30T15:22:06.282-10:00Report on Agent Development Stimulation PlatformIn the <a href="http://www2.hawaii.edu/%7Enreed/ics606/assign2.html">Assignment 3 of <span class="blsp-spelling-error" id="SPELLING_ERROR_0">ICS</span>606</a>, I was supposed to install the <a href="http://www.robocuprescue.org/"><span class="blsp-spelling-error" id="SPELLING_ERROR_1">Robocup</span> Rescue system</a> and do some experimental agent development upon it. However, even compile the system came out to be nothing trivial. The system is written in both C/C++ and Java. The latest version is back to Mar 2007. They use both <span class="blsp-spelling-error" id="SPELLING_ERROR_2">GCC</span> and <span class="blsp-spelling-error" id="SPELLING_ERROR_3">JDK</span> to compile the system, but since their latest release, both these two compilers have updated quite a bit. As a result, the code cannot be compiled using the latest version of the compilers. Moreover, as although the system is claimed to be platform-independent, its <span class="blsp-spelling-error" id="SPELLING_ERROR_4">makefile</span> do use some parameter that is not available to Macintosh (like -<span class="blsp-spelling-error" id="SPELLING_ERROR_5">soname</span>), and the source code contain some function that has no Macintosh version(like <span class="blsp-spelling-error" id="SPELLING_ERROR_6">pthread</span>_yield()). The only <span class="blsp-spelling-corrected" id="SPELLING_ERROR_7">guaranteed</span> is Unix, in the state when their latest version released.<br /><br />I have tried to compile it in Mac OS X 10.5, Windows XP SP3 and Ubuntu 9.04, with the latest compilers. None of them has any luck to pass the compiling, and the error given in these three platform are different.<br /><br />In order to successful compile the system, the user have three choices. The first way, also the hard way, is to fix all the compile failures to match the compiler of the user's enviornment. The second way, which is theorictical, is to configure the compile system to compatible to the state of the release day. The third, which is somehow tricky but most easy way, is to install a stand-alone Linux using the old build. The easier way is to install that in a virtual machine. It is proofed to work to install the Ubuntu 6.10(Edgy Eft).<br /><br />On contrary, the <a href="http://robocode.sourceforge.net/">Robocode</a>, which I got to know from a classmate's presentation, is much user-friendly. The procedure from downloading to start using it is quite straight forward. The installation package execute correctly and I can start writing my own agent in 10 minutes!<br /><br />In conculsion, the Robocup platform is ill designed and extremely user-unfriendly, while Robocode is a much better platform for agent stimulation and easy to use.Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com0tag:blogger.com,1999:blog-3809985069441923745.post-79523796959746712712009-04-13T23:31:00.002-10:002009-04-13T23:44:05.009-10:00Boswell continue?Last week I started working on the course project of the agent class. The project I pick is based on Hackystat, and is a continue study of an existed topic: boswell/tickertape, a auto blogging agent for software development. While working on it, I am kind of lost my way. There is no directly related research about that. But there are many likely related fields, such as language processing, knowledge base, etc. The search field is so large that I am lost inside it. All potential related fields are so big to understand in short time. However, without understanding, it is hard to tell if concepts and technics from it will be useful or not. Currently, I just put my hope in language processing. There is some study of it and also using knowledge base concepts. I hope I can get a breakpoint from there.<br /><br />This research is not directly related to my thesis. But it is an interesting research of Hackystat. Hopefully I can end up with some useful insight after finish the course project, if I can indeed finish it well....Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com0tag:blogger.com,1999:blog-3809985069441923745.post-20687898126078783442009-04-06T22:58:00.002-10:002009-04-06T23:24:35.055-10:00Stuck in course workAnother week done nothing about <span class="blsp-spelling-error" id="SPELLING_ERROR_0">Hackystat</span> nor thesis... But it was a busy week because I was stuck in my course work during the whole week.<br /><br />In the first half of the week, I was preparing the midterm of <span class="blsp-spelling-error" id="SPELLING_ERROR_1">ICS</span>606 Autonomous Agent, which is on Wednesday. After that, I switch to the assignment of <span class="blsp-spelling-error" id="SPELLING_ERROR_2">ICS</span>621 Analysis of Algorithm. The assignment is to design an algorithm to solve the <a href="http://www2.hawaii.edu/%7Esugihara/course/ics621s09/assign2_PowerGridLoadShedding.html">power grid load shedding problem</a>. It is an NP-complete problem, and it is about directed weighted graph. It took me the whole week thinking of a better algorithm. Then at the end it came out to be worst than the brainless enumeration. That is quite frustrating.<br /><br />This this week, I will have to start the almost-forgot course project of Autonomous Agent. The project I choose is to further develop the <span class="blsp-spelling-error" id="SPELLING_ERROR_3">Tickertape</span> in <span class="blsp-spelling-error" id="SPELLING_ERROR_4">Hackystat</span> project, to grant it more intelligence to act as human beings. The first step will be constructing "knowledge" about user's developing behaviours from <span class="blsp-spelling-error" id="SPELLING_ERROR_5">hackystat</span> sensor data. The hard part is how to design the structure of that knowledge in a way that it not only has good representation power, but also facilitate to generate human language sentence. I am not sure where to start, design the knowledge first then the way to express it, or <span class="blsp-spelling-corrected" id="SPELLING_ERROR_6">the opposit way</span>.<br /><br />I hope I will be able to finish the course work faster and left some time for my other jobs.Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com0tag:blogger.com,1999:blog-3809985069441923745.post-60739001308487888902009-03-30T19:52:00.004-10:002009-03-30T20:24:36.377-10:00Taking a break and gsoc 2009As the name tells, I took a break during spring break. =P<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">Ideas of Google Summer of Code</span></span><br /><br />In the last meeting with Philip, he provides me an idea of utilizing Issues data into Hackystat, from the bottom of collecting and sending data to the top in Software ICU analysis. In the middle there are an associated DPD analysis and a set of Telemetry analyses. The Issues data is an essential sign of health of project management, but long missed in Hackystat version 8. Additionally, this is a good chance to work all through the system, which I did not experience yet. This proposal contains enough work for 3 months, so I used this idea in my application to GSoC 2009.<br /><br />Before that, I have another idea: provide a facilitating way to deploy service of Hackystat. The first part is easy way to deploy sensorbase upon various database implementation. Currently, users have to implement the interface in Java code by themselves and complie the system. I want to find a way to separate the database access part into a standalone componenet that user did not have to complie sensorbase everytime there is update of sensorbase. The database access component requires much less update in functionality than sensorbase, thus less, if any expect bug fix, update/recomplie required. I may also do the implementation for some popluar database such as MySQL, IBM DB2, Oracle and MS SQL Server. The second part is an administration tool to lauch Hackystat service such as sensorbase, dpd, telemetry and projectbrowser. It provides GUI to configure settings, and capability to hide the command-line windows, make Hackystat runs in backgroud like most system services do. I did not familiar with either database implementation nor GUI configuration building. Thus estismated work is unknown for me. I expect more time in research that coding to accomplish this.Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com0tag:blogger.com,1999:blog-3809985069441923745.post-19964198419449617432009-03-23T22:44:00.003-10:002009-03-23T23:19:29.505-10:00Revise my thesis<span style="font-weight: bold;font-size:130%;" >State of manual report tool</span><br /><br />The manual report tool is finished for basic but complete functionality. The UI is similar with the figures <a href="http://zsx-engineering-log.blogspot.com/2009/03/more-analysis-on-log-data.html">post before</a>, except that the "Labels" field is removed and labels is expected to input in "Resource" field. This is actually the way to construct the resource field in sensor data. Making it this way makes user less confused when they see their "labels" shown in the resource field in history panel.<br /><br />As discussed before, history panel manipulate sensor data piece by piece, no grouping function is provided.<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">Revise my master thesis</span></span><br /><br />I start revising my thesis from the "portfolio" version to a "software ICU" version. The introduction is being totally rewritten to introduce the idea from different angle. I am reviewing recent tech-reports about Hackystat and software ICU, which including <a href="http://csdl.ics.hawaii.edu/techreports/09-02/09-02.pdf">09-02</a>, <a href="http://csdl.ics.hawaii.edu/techreports/09-03/09-03.pdf">09-03</a> and <a href="http://csdl.ics.hawaii.edu/techreports/09-07/09-07.pdf">09-07</a> to get ideas of the start point.<br /><br />Most of other parts, such as the related work section, can remain the same.Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com0tag:blogger.com,1999:blog-3809985069441923745.post-76890529812246269612009-03-16T21:43:00.002-10:002009-03-16T22:12:39.530-10:00Self-report tool is readyAfter a little talk to Philip, I realize that showing the raw sensor data may even better than grouping them into events, because in that way we can give user more control over their data. The initial motivation of add that "event management" feature is in case of editing data. However, for the near goal, we will not provide the editing feature in the manage panel. If user think there is error in their input, just delete the data and resend it again. When managing the raw data, there is a possible trick to shorten the time by delete some of the data. The other reason I wanted that grouping feature is trying to make sure users will correctly delete their data, not leave unexpected data in sensorbase. However, in either way, users have to take responsibility to their data. The additional feature will not ensure they will make less mistake than without it. In contract, if the additional is less robust than it appear, users might pay less attention to their data's completeness than they will do with raw data, which may lead to more defect data. Therefore, after this second thought, I decide to leave the responsibility of the data's completeness back to the owners before a powerful and reliable enough manager exists.<br /><br />Plan for this week is to finish the self-report tool. Everything is ready actually, just need more test of sending out data. After that, thesis!Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com0tag:blogger.com,1999:blog-3809985069441923745.post-91889373031179171862009-03-09T18:06:00.004-10:002009-03-09T18:47:07.026-10:00More analysis on log data<span style="font-size:130%;"><span style="font-weight: bold;">Accomplish of last week</span></span><br />1. Tech-report of Hackystat evaluation 2008 is revised. More analyses of data on per student bias are added in order to gain further insight into the logged and survey data. It is interesting to find that some students' responses are far from their reality: the use frequencies they claimed are much lower than the actual frequencies logged by the system. Though it is hard to verify if the error is intended or not, it does reveal some interesting point from their answers to other question: those students are the ones who concerned with sharing their data, especially DevTime and Commit. It is reasonable to infer that they were not happy with the data showing their laziness to their teammates.<br /><br />2. All functionality for initial release of the self-report tool is complete. Currently the application takes a time period denoted by start and end time, resource file, tools and label to generate the DevTime data. The UI is shown below.<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_pRQYn9_Y5Ig/SbXr_SxY4LI/AAAAAAAAAak/jI3voGDowUA/s1600-h/self-report-new.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 258px;" src="http://1.bp.blogspot.com/_pRQYn9_Y5Ig/SbXr_SxY4LI/AAAAAAAAAak/jI3voGDowUA/s320/self-report-new.jpg" alt="" id="BLOGGER_PHOTO_ID_5311410808156643506" border="0" /></a><br />Also the application is capable to manage the data you sent. It is able to retrieve data in a given data, filter the data to a given tool if available, show it on a table, and allow user to delete data from it. The following image shows an example of this feature. The image is captured on the experimental implementation that the data is not filter to be self-reported only, which will be implemented in actual release.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_pRQYn9_Y5Ig/SbXs7oHUW9I/AAAAAAAAAas/Zuz9kYqty3M/s1600-h/self-report-manage.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 258px;" src="http://2.bp.blogspot.com/_pRQYn9_Y5Ig/SbXs7oHUW9I/AAAAAAAAAas/Zuz9kYqty3M/s320/self-report-manage.jpg" alt="" id="BLOGGER_PHOTO_ID_5311411844677917650" border="0" /></a>The current state of the manager is actually not quite useful, or even annoying. This is because the approach of devtime sensor data: a piece of data make a five mintes period as active devtime. So for every event that user reported, there is not a single data relative to it, instead, there are a set of data, each departed by five mintes, to present the length of the action period. When editing, these pieces of data are shown and treated as separated instance, and are deletable separately. This does kind of distrupting the concept behind the sensor data. In order to avoid this, the data should grouped by events and managed as events. This will be the next priority of this project.<br /><br /><span style="font-size:130%;"><span style="font-weight: bold;">Plan for this week</span></span><br /><br />I have a paper presentation on Wednesday morning, that will probably take all my time till then. But after that, I can have a small break from my course work and put more time to the lab projects and my thesis. So here is the plan for this week:<br /><ol><li>Continue the self-report tool. It is very close to it designed funtionality now. </li><li>Revise my thesis.</li></ol>Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com0tag:blogger.com,1999:blog-3809985069441923745.post-4845545612090068502009-03-02T17:25:00.003-10:002009-03-02T17:43:26.080-10:00Presentation Finished!The biggest this for me last week is the presentation of my thesis project on seminar course. My slides can be found <a href="http://docs.google.com/Presentation?id=dht87b9_8f7gc7kd9">here</a>. It was the biggest presentation I ever made and make me nervous to dead because I did not get much time to practice the talk. Fortunately it came out to be a successful one. I was planning to revise my thesis before start preparing the presentation but I found I was running out of time. So the thesis is still untouched yet. As discuss with Philip and Robert, my presentation did not include enough information about the evaluation result. I was thinking adding more to the slide but the result is too literal and long that it is hard to summarize good with a few slides. And insufficient analyze of the logging data is another reason of this difficulty. From Philip's inspiration, I started making more analysis charts over the data and they do reveal some additional information. They will soon be added to the evaluation tech-report.<br /><br />Plan for this week:<br /><ol><li>Finish further analysis of the data and add the new result to the evaluation tech-report.</li><li>Finish the first release of self-report sensor. The remain thing for initial release is the ability to delete self-reported data. This is most involved with displaying an inner data object with <a href="http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/JTable.html">JTable</a>.</li><li>Revise my thesis. It is long postponed and should be caught up sooner. I still want to finish the thesis before submission deadline in order to keep the initiative of my graduation.<br /></li></ol>Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com0tag:blogger.com,1999:blog-3809985069441923745.post-73259101364104039002009-02-23T18:03:00.002-10:002009-02-23T18:32:06.696-10:00Common Lisp to my thesisDuring the last week, little work is been put into neither the self-report tool nor my thesis, because most of the time is put on the assignment of ICS606 Autonomous Agent. This assignment took me a whole week because it is based on Lisp. It requires to enhance a vacuum agent which is written in Lisp. Though I had taken the undergraduate class about Lisp, I were near to novice because firstly I did not experience writing functions, methods and structures in Lisp in that class, and secondly, I had nearly forgotten everything I learn in that class. It took me about two day to pick up Lisp and advance to object-oriented like feature. Meanwhile, I found the book <a href="http://www.gigamonkeys.com/book/">Practical Common Lisp</a> is pretty awesome, and it is available on web! It actually explain Lisp much better than the undergraduate class. After being familiar with Lisp, I did find Lisp is pretty good in program the agent because represent and interpret data is unbelievable facilitated. It gives more freedom than other language ever possible give, though it is sometime same as freedom to make mistake. =P<br /><br />In this week, the priority is to revise my thesis. Actually the biggest task in this week is the seminar presentation on Thursday. Thus revising my thesis is one of the best way to coordinate ideas in the presentation. After not so many presentation in class, I feel my biggest problem is not practicing the start and detail besides slides. What I did in my previous experience is mostly like to outline the content to slides, and only review the detail over my head. When presenting, because of nervous, I often did not start the talk very good, that cause me even more nervous usually, and forgot what I had prepare in mind, then doing even worse. So I got stuck into a vicious circle and end up being reading the words in the slide. This time, I will trying to rehearsal some times before, in order to get prepared in both content and confidence.Shaoxuan Zhanghttp://www.blogger.com/profile/08830851697492669175noreply@blogger.com0