Moved educational plugin for PyCharm to community (from github cscenter repository)
authorEkaterina Tuzova <Ekaterina.Tuzova@jetbrains.com>
Wed, 13 Aug 2014 14:14:47 +0000 (18:14 +0400)
committerEkaterina Tuzova <Ekaterina.Tuzova@jetbrains.com>
Wed, 13 Aug 2014 14:14:47 +0000 (18:14 +0400)
Merge remote-tracking branch 'educational/master'

238 files changed:
1  2 
python/edu/gen/icons/StudyIcons.java
python/edu/resources/com/jetbrains/python/edu/introduction_course/OVERVIEW
python/edu/resources/com/jetbrains/python/edu/introduction_course/course.json
python/edu/resources/com/jetbrains/python/edu/introduction_course/hints/lesson1.task1.docs
python/edu/resources/com/jetbrains/python/edu/introduction_course/hints/lesson1.task2.docs
python/edu/resources/com/jetbrains/python/edu/introduction_course/hints/lesson2.task1.docs
python/edu/resources/com/jetbrains/python/edu/introduction_course/hints/lesson2.task2.docs
python/edu/resources/com/jetbrains/python/edu/introduction_course/hints/lesson2.task3.docs
python/edu/resources/com/jetbrains/python/edu/introduction_course/hints/lesson2.task4.1.docs
python/edu/resources/com/jetbrains/python/edu/introduction_course/hints/lesson2.task4.2.docs
python/edu/resources/com/jetbrains/python/edu/introduction_course/hints/lesson2.task5.docs
python/edu/resources/com/jetbrains/python/edu/introduction_course/hints/lesson2.task6.docs
python/edu/resources/com/jetbrains/python/edu/introduction_course/hints/lesson2.task7.docs
python/edu/resources/com/jetbrains/python/edu/introduction_course/hints/lesson3.task1.docs
python/edu/resources/com/jetbrains/python/edu/introduction_course/hints/lesson3.task10.1.docs
python/edu/resources/com/jetbrains/python/edu/introduction_course/hints/lesson3.task10.2.docs
python/edu/resources/com/jetbrains/python/edu/introduction_course/hints/lesson3.task2.docs
python/edu/resources/com/jetbrains/python/edu/introduction_course/hints/lesson3.task3.docs
python/edu/resources/com/jetbrains/python/edu/introduction_course/hints/lesson3.task4.docs
python/edu/resources/com/jetbrains/python/edu/introduction_course/hints/lesson3.task5.docs
python/edu/resources/com/jetbrains/python/edu/introduction_course/hints/lesson3.task6.docs
python/edu/resources/com/jetbrains/python/edu/introduction_course/hints/lesson3.task7.docs
python/edu/resources/com/jetbrains/python/edu/introduction_course/hints/lesson3.task8.docs
python/edu/resources/com/jetbrains/python/edu/introduction_course/hints/lesson3.task9.docs
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson1/task1/hello_world.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson1/task1/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson1/task1/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson1/task2/comments.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson1/task2/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson1/task2/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson10/task1/input.txt
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson10/task1/input1.txt
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson10/task1/read_file.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson10/task1/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson10/task1/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson10/task2/output.txt
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson10/task2/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson10/task2/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson10/task2/write_to_file.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson2/task1/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson2/task1/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson2/task1/variable_definition.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson2/task2/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson2/task2/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson2/task2/undefined_variable.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson2/task3/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson2/task3/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson2/task3/variable_type.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson2/task4/arithmetic_operators.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson2/task4/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson2/task4/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson2/task5/assignments.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson2/task5/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson2/task5/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson2/task6/boolean_operators.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson2/task6/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson2/task6/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson2/task7/comparison_operators.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson2/task7/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson2/task7/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task1/concatenation.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task1/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task1/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task10/string_formatting.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task10/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task10/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task2/string_multiplication.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task2/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task2/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task3/string_indexing.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task3/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task3/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task4/negative_indexing.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task4/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task4/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task5/slicing.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task5/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task5/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task6/in_operator.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task6/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task6/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task7/len_function.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task7/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task7/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task8/character_escaping.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task8/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task8/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task9/string_methods.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task9/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson3/task9/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson4/task1/lists.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson4/task1/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson4/task1/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson4/task2/list_operations.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson4/task2/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson4/task2/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson4/task3/list_items.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson4/task3/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson4/task3/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson4/task4/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson4/task4/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson4/task4/tuples.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson4/task5/dicts.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson4/task5/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson4/task5/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson4/task6/dict_key_value.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson4/task6/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson4/task6/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson4/task7/in_keyword.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson4/task7/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson4/task7/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson5/task1/boolean_operators.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson5/task1/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson5/task1/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson5/task2/boolean_order.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson5/task2/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson5/task2/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson5/task3/if_statement.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson5/task3/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson5/task3/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson5/task4/else_elif.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson5/task4/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson5/task4/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson6/task1/for_loop.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson6/task1/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson6/task1/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson6/task2/for_string.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson6/task2/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson6/task2/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson6/task3/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson6/task3/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson6/task3/while_loop.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson6/task4/break_keyword.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson6/task4/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson6/task4/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson6/task5/continue_keyword.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson6/task5/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson6/task5/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson7/task1/functions.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson7/task1/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson7/task1/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson7/task2/param_args.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson7/task2/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson7/task2/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson7/task3/return_keyword.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson7/task3/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson7/task3/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson7/task4/default_parameter.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson7/task4/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson7/task4/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson8/task1/class_definition.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson8/task1/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson8/task1/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson8/task2/access_variable.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson8/task2/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson8/task2/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson8/task3/access_variable.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson8/task3/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson8/task3/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson8/task4/self_parameter.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson8/task4/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson8/task4/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson8/task5/init_method.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson8/task5/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson8/task5/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson9/task1/calculator.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson9/task1/imports.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson9/task1/my_module.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson9/task1/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson9/task1/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson9/task2/builtin_modules.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson9/task2/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson9/task2/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson9/task3/calculator.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson9/task3/from_import.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson9/task3/my_module.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson9/task3/task.html
python/edu/resources/com/jetbrains/python/edu/introduction_course/lesson9/task3/tests.py
python/edu/resources/com/jetbrains/python/edu/introduction_course/test_helper.py
python/edu/resources/com/jetbrains/python/edu/user_tester.py
python/edu/resources/icons.com.jetbrains.python.edu/Run.png
python/edu/resources/icons.com.jetbrains.python.edu/ShortcutReminder.png
python/edu/resources/icons.com.jetbrains.python.edu/WatchInput.png
python/edu/resources/icons.com.jetbrains.python.edu/add.png
python/edu/resources/icons.com.jetbrains.python.edu/checked.png
python/edu/resources/icons.com.jetbrains.python.edu/failed.png
python/edu/resources/icons.com.jetbrains.python.edu/fatalError.png
python/edu/resources/icons.com.jetbrains.python.edu/icon.jpg
python/edu/resources/icons.com.jetbrains.python.edu/next.png
python/edu/resources/icons.com.jetbrains.python.edu/playground.png
python/edu/resources/icons.com.jetbrains.python.edu/prev.png
python/edu/resources/icons.com.jetbrains.python.edu/refresh.png
python/edu/resources/icons.com.jetbrains.python.edu/refresh24.png
python/edu/resources/icons.com.jetbrains.python.edu/resolve.png
python/edu/resources/icons.com.jetbrains.python.edu/resolve_dark.png
python/edu/resources/icons.com.jetbrains.python.edu/showHint.png
python/edu/resources/icons.com.jetbrains.python.edu/unchecked.png
python/edu/src/META-INF/plugin.xml
python/edu/src/com/jetbrains/python/edu/StudyDirectoryProjectGenerator.java
python/edu/src/com/jetbrains/python/edu/StudyDocumentListener.java
python/edu/src/com/jetbrains/python/edu/StudyEditorFactoryListener.java
python/edu/src/com/jetbrains/python/edu/StudyHighlightErrorFilter.java
python/edu/src/com/jetbrains/python/edu/StudyInstructionPainter.java
python/edu/src/com/jetbrains/python/edu/StudyResourceManger.java
python/edu/src/com/jetbrains/python/edu/StudyTaskManager.java
python/edu/src/com/jetbrains/python/edu/StudyUtils.java
python/edu/src/com/jetbrains/python/edu/actions/CheckAction.java
python/edu/src/com/jetbrains/python/edu/actions/NextTaskAction.java
python/edu/src/com/jetbrains/python/edu/actions/NextWindowAction.java
python/edu/src/com/jetbrains/python/edu/actions/PrevWindowAction.java
python/edu/src/com/jetbrains/python/edu/actions/PreviousTaskAction.java
python/edu/src/com/jetbrains/python/edu/actions/RefreshTaskAction.java
python/edu/src/com/jetbrains/python/edu/actions/ShowHintAction.java
python/edu/src/com/jetbrains/python/edu/actions/StudyRunAction.java
python/edu/src/com/jetbrains/python/edu/actions/TaskNavigationAction.java
python/edu/src/com/jetbrains/python/edu/actions/WatchInputAction.java
python/edu/src/com/jetbrains/python/edu/course/Course.java
python/edu/src/com/jetbrains/python/edu/course/CourseInfo.java
python/edu/src/com/jetbrains/python/edu/course/Lesson.java
python/edu/src/com/jetbrains/python/edu/course/LessonInfo.java
python/edu/src/com/jetbrains/python/edu/course/Stateful.java
python/edu/src/com/jetbrains/python/edu/course/StudyStatus.java
python/edu/src/com/jetbrains/python/edu/course/Task.java
python/edu/src/com/jetbrains/python/edu/course/TaskFile.java
python/edu/src/com/jetbrains/python/edu/course/TaskWindow.java
python/edu/src/com/jetbrains/python/edu/course/UserTest.java
python/edu/src/com/jetbrains/python/edu/editor/StudyEditor.java
python/edu/src/com/jetbrains/python/edu/editor/StudyFileEditorProvider.java
python/edu/src/com/jetbrains/python/edu/projectView/StudyDirectoryNode.java
python/edu/src/com/jetbrains/python/edu/projectView/StudyTreeStructureProvider.java
python/edu/src/com/jetbrains/python/edu/ui/StudyCondition.java
python/edu/src/com/jetbrains/python/edu/ui/StudyNewProjectPanel.form
python/edu/src/com/jetbrains/python/edu/ui/StudyNewProjectPanel.java
python/edu/src/com/jetbrains/python/edu/ui/StudyProgressBar.java
python/edu/src/com/jetbrains/python/edu/ui/StudyToolWindowFactory.java
python/edu/src/com/jetbrains/python/edu/ui/TestContentPanel.java
python/edu/testData/course.json
python/edu/tests/JsonParserTest.java

index 0000000000000000000000000000000000000000,c64625e1d0ea8c77cc029542d982009079b6bf4f..a212ebde3b8325698fdb72cc38834a8f565e17fe
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,26 +1,26 @@@
 -  public static final Icon UncheckedTask = load("/icons/unchecked.png");
+ package icons;
+ import com.intellij.openapi.util.IconLoader;
+ import javax.swing.*;
+ public class StudyIcons {
+   private static Icon load(String path) {
+     return IconLoader.getIcon(path, StudyIcons.class);
+   }
+   public static final Icon Resolve = load("/icons/resolve.png"); // 24*24
 -  public static final Icon WatchInput = load("/icons/WatchInput.png");
++  public static final Icon UncheckedTask = load("/icons/com.jetbrains.python.edu/unchecked.png");
+   public static final Icon CheckedTask = load("/icons/checked.png");
+   public static final Icon FailedTask = load("/icons/failed.png");
+   public static final Icon Prev = load("/icons/prev.png");
+   public static final Icon Next = load("/icons/next.png");
+   public static final Icon Run = load("/icons/Run.png");
+   public static final Icon ShortcutReminder = load("/icons/ShortcutReminder.png");
++  public static final Icon WatchInput = load("/icons/com.jetbrains.python.edu/WatchInput.png");
+   public static final Icon Refresh24 = load("/icons/refresh24.png");
+   public static final Icon Refresh = load("/icons/refresh.png");
+   public static final Icon Playground = load("/icons/playground.png");
+   public static final Icon ErrorIcon = load("/icons/fatalError.png");
+   public static final Icon Add = load("/icons/add.png");
+ }
index 0000000000000000000000000000000000000000,5ba5366bc878f5b3de19b76424ef1d8446279403..5ba5366bc878f5b3de19b76424ef1d8446279403
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,56d6d91782afea08e344bdbf3f75ed5bb6e01ef1..56d6d91782afea08e344bdbf3f75ed5bb6e01ef1
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,f2a407153a9d98d40e05d58657e191759f12b61f..f2a407153a9d98d40e05d58657e191759f12b61f
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,df54db922179da1bbf195e169daeaf86cd9df237..df54db922179da1bbf195e169daeaf86cd9df237
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,a5f682955a2b2e2d35338667d26229691a44a5c3..a5f682955a2b2e2d35338667d26229691a44a5c3
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,f20ae61e8b3706079dd9414a0c30f4f9eeeee058..f20ae61e8b3706079dd9414a0c30f4f9eeeee058
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,d16eb650937f47c14b75af5cc4e9821be8be03f7..d16eb650937f47c14b75af5cc4e9821be8be03f7
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,6753bb85aeb4663753b3422d17d187ddf9f510a6..6753bb85aeb4663753b3422d17d187ddf9f510a6
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,fa22a3c7dfbe2788d979f0822c1ab02a99aaf1a4..fa22a3c7dfbe2788d979f0822c1ab02a99aaf1a4
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,1ce847b3bc35d4f896cb1806f99d3054ad26f621..1ce847b3bc35d4f896cb1806f99d3054ad26f621
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,dce14f8e88c1bfbebc70e9f2337a23f0bc4ad9bf..dce14f8e88c1bfbebc70e9f2337a23f0bc4ad9bf
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,0dd2ea8ec9d90beff14e81ff831e24908fb9500e..0dd2ea8ec9d90beff14e81ff831e24908fb9500e
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,9f14a47380b4e1aafaace16f6f48aa2efc0e8dac..9f14a47380b4e1aafaace16f6f48aa2efc0e8dac
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,1c7ec1eeed23fae626d5243bcec457fcb7ad4fda..1c7ec1eeed23fae626d5243bcec457fcb7ad4fda
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,e4800345eaf24da539387a6a6c1e4e78a54b5b80..e4800345eaf24da539387a6a6c1e4e78a54b5b80
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,1187be55461242df5b0dabeafd31ce71f8592abe..1187be55461242df5b0dabeafd31ce71f8592abe
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,2cd5d4aa4598230ef424a516cc6e9d9ee7a567b3..2cd5d4aa4598230ef424a516cc6e9d9ee7a567b3
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,c747fa98d59d941b7ddac9cbfb8863aac5605a17..c747fa98d59d941b7ddac9cbfb8863aac5605a17
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,59d20736ef96e26ca5234930ada5c40ef855bded..59d20736ef96e26ca5234930ada5c40ef855bded
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,b9c2478b8f2f833764e2418fa2d659051dc08887..b9c2478b8f2f833764e2418fa2d659051dc08887
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,1fe2b72179eb3905ee8132c4a88b9e97d5511d0c..1fe2b72179eb3905ee8132c4a88b9e97d5511d0c
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,4760b462a297f11cde0055ccad36f9337a34f1cd..4760b462a297f11cde0055ccad36f9337a34f1cd
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,436f0e1e54fc6b979cf7feaea7c008afd84857d0..436f0e1e54fc6b979cf7feaea7c008afd84857d0
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,65f527353e8529487d5fdd50e3d155c3ed13d9d6..65f527353e8529487d5fdd50e3d155c3ed13d9d6
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,d9170f42e26424b84eeca2d94022f2b553ce6a5e..d9170f42e26424b84eeca2d94022f2b553ce6a5e
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,8e6b916e291ee92966f19a38fcb91caff36a7b93..8e6b916e291ee92966f19a38fcb91caff36a7b93
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,0d29edb76a627b86e740b8a8d0b6c214f6bf654e..0d29edb76a627b86e740b8a8d0b6c214f6bf654e
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,8f9a9289a90a60f7625ac715a0dded57dd159db7..8f9a9289a90a60f7625ac715a0dded57dd159db7
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,73393620ee8496c812e58bed91c1a2a6fab3bd53..73393620ee8496c812e58bed91c1a2a6fab3bd53
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,d12392ebe877cf20b821716c674679b51607b69f..d12392ebe877cf20b821716c674679b51607b69f
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,547f7db34b4078b54c9b1a084134aff3db3c0ff6..547f7db34b4078b54c9b1a084134aff3db3c0ff6
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,1c7daa73605c774674df2469776e4eae9bd41898..1c7daa73605c774674df2469776e4eae9bd41898
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,6e3840528d6b94b89e8e1266efc5372c9466e4ae..6e3840528d6b94b89e8e1266efc5372c9466e4ae
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,7a2dfa2fc8ff9cb4cc8c98651c96cd0db0c71e61..7a2dfa2fc8ff9cb4cc8c98651c96cd0db0c71e61
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,48ba060e56733791ae241a3553deeb1b23e270ad..48ba060e56733791ae241a3553deeb1b23e270ad
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,49aa622ae4012c1b95fbf8bdabc4c9481ca4c0ba..49aa622ae4012c1b95fbf8bdabc4c9481ca4c0ba
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,befef3218c848e1b3c9f078bd8177647c168380d..befef3218c848e1b3c9f078bd8177647c168380d
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,4f6adabfa658ae453a90e1aac6a577608507d83f..4f6adabfa658ae453a90e1aac6a577608507d83f
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,243f88df079168001562cfd3ab8d56a924dfa3cb..243f88df079168001562cfd3ab8d56a924dfa3cb
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,8b345b29e99cf383c9d1132571bd38f6e27bb634..8b345b29e99cf383c9d1132571bd38f6e27bb634
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,1f0069cf901ed1df7d16cef9b3a057a7557c8d9c..1f0069cf901ed1df7d16cef9b3a057a7557c8d9c
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,ad7ae31e18d9cee69cea8bc86c3b449005bad777..ad7ae31e18d9cee69cea8bc86c3b449005bad777
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,ef0297d64a65453497270419719d27191129f66e..ef0297d64a65453497270419719d27191129f66e
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,cef61eeffd6f0fb7d4e02332960768c15a69992f..cef61eeffd6f0fb7d4e02332960768c15a69992f
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,f3f046c0203aa0bf7819d45d74092302e27e4130..f3f046c0203aa0bf7819d45d74092302e27e4130
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,8aa4d2c969df865cfc08e3fd40b0e708e6609dd5..8aa4d2c969df865cfc08e3fd40b0e708e6609dd5
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,f69fa5a7961e8a78d951739f135fb58f02b15290..f69fa5a7961e8a78d951739f135fb58f02b15290
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,e0d88ee3987164d8375aa459d45fd2fa2c70aa5f..e0d88ee3987164d8375aa459d45fd2fa2c70aa5f
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,b190c699fb84d9b4752c7a57d1d2762af51afc5a..b190c699fb84d9b4752c7a57d1d2762af51afc5a
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,206c07f2ad1ce86a6fa8d453df62c657cd7e6032..206c07f2ad1ce86a6fa8d453df62c657cd7e6032
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,235030d476af50b57a71ce713b520ccc821b45ca..235030d476af50b57a71ce713b520ccc821b45ca
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,c1a9b8c1166cf5b535b3e7d22b5a91b184920c4c..c1a9b8c1166cf5b535b3e7d22b5a91b184920c4c
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,300caf57469af792d79268567e558654c52271d6..300caf57469af792d79268567e558654c52271d6
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,01aea30a00df0e5d19eb1f7b28af82284a3091cc..01aea30a00df0e5d19eb1f7b28af82284a3091cc
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,99c45c97f4760f9e4b6bf02f8894b2aab1b19e6e..99c45c97f4760f9e4b6bf02f8894b2aab1b19e6e
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,438f72b3a3966f96c26986906b1537e1025de143..438f72b3a3966f96c26986906b1537e1025de143
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,c01606f7ea507e8db9b8576c200073eedb84b9f6..c01606f7ea507e8db9b8576c200073eedb84b9f6
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,acc826c63ef9fc7342200b3c9b7af5304e0ee1f0..acc826c63ef9fc7342200b3c9b7af5304e0ee1f0
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,fbbd943f32a075e495edea7e9f6968c0e816b45b..fbbd943f32a075e495edea7e9f6968c0e816b45b
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,3193a0caeb07506b751190bdb2c1c01c80fc23ec..3193a0caeb07506b751190bdb2c1c01c80fc23ec
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,1863fbd4f1d1ade73f768391479bbbbbe016df1e..1863fbd4f1d1ade73f768391479bbbbbe016df1e
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,b36816b204bed1c7cc4a397bd360230f4ee24a83..b36816b204bed1c7cc4a397bd360230f4ee24a83
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,6da033cd99fb8af303ffe5e5c94d25883bf2b883..6da033cd99fb8af303ffe5e5c94d25883bf2b883
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,c0115247489e70ecfdd71c12509c0cc2c9ee5c3f..c0115247489e70ecfdd71c12509c0cc2c9ee5c3f
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,06cd9fa71200e8d1fb3b13f0da27ef90df32529f..06cd9fa71200e8d1fb3b13f0da27ef90df32529f
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,f8d696a3c31e03a46a121bc6bf30e9aae47df8ec..f8d696a3c31e03a46a121bc6bf30e9aae47df8ec
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,1bbd57da48dc959789eefe4c2811b13432ea5731..1bbd57da48dc959789eefe4c2811b13432ea5731
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,0a66572cecc5d6186271ed4f83d7d56f509f9bac..0a66572cecc5d6186271ed4f83d7d56f509f9bac
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,549f44e54d8487f2d00dc87aed1dc7712059fb7a..549f44e54d8487f2d00dc87aed1dc7712059fb7a
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,af55919b77b45357673946d0f27270abc83e5055..af55919b77b45357673946d0f27270abc83e5055
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,4026c98d226cb26543f711b7f2781efe7528dce0..4026c98d226cb26543f711b7f2781efe7528dce0
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,5fc144b2ba0706cf570db52dd29fd3d076caf073..5fc144b2ba0706cf570db52dd29fd3d076caf073
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,b2364fc4a3a291375a0cb7867dfb381b8fa0002c..b2364fc4a3a291375a0cb7867dfb381b8fa0002c
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,8c996adc5e8b1755bb434e83cbc59bc2199ccb97..8c996adc5e8b1755bb434e83cbc59bc2199ccb97
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,e8a33464106e17875d343e2036284ab199df1fa5..e8a33464106e17875d343e2036284ab199df1fa5
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,8e714a3c29ab53747b2c297bea0be550683ab650..8e714a3c29ab53747b2c297bea0be550683ab650
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,da73043d55f68ad4fdf4c835e6ff781baede26d2..da73043d55f68ad4fdf4c835e6ff781baede26d2
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,90867e6f2f4004baf2b50a9f3c0a736c2445174e..90867e6f2f4004baf2b50a9f3c0a736c2445174e
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,cf2536a52cbc62574017b6d04e64e8fe7fcf46fc..cf2536a52cbc62574017b6d04e64e8fe7fcf46fc
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,3bfa811876f076a7c23e8d81638a1542f5f26e2f..3bfa811876f076a7c23e8d81638a1542f5f26e2f
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,7d02906860d5a430ee9f7965477821d5ac285446..7d02906860d5a430ee9f7965477821d5ac285446
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,a531b49e16187bb4290bcf3c639b6a18f34a4614..a531b49e16187bb4290bcf3c639b6a18f34a4614
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,7d66adb2ce63ba1a1bb0f31098137ad18d305c7a..7d66adb2ce63ba1a1bb0f31098137ad18d305c7a
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,67d731c83ae566d54ccebaa078e04d7268db2de5..67d731c83ae566d54ccebaa078e04d7268db2de5
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,017e5111d1a3ada5256bcfd98f5348de706d1cf2..017e5111d1a3ada5256bcfd98f5348de706d1cf2
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,104be26a84fd02ce7ff2318a14e3a822850179f7..104be26a84fd02ce7ff2318a14e3a822850179f7
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,88bbbe770f723b0ff0170af494c8626dd6e6ed49..88bbbe770f723b0ff0170af494c8626dd6e6ed49
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,cf98278ceb403658d7856bb7bb612a590a766d1c..cf98278ceb403658d7856bb7bb612a590a766d1c
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,3f16f93f52a52554a4f6df1e6d8009b3a79a0b86..3f16f93f52a52554a4f6df1e6d8009b3a79a0b86
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,485aa5dac62fee7bba2798ca4d6bff64554b8404..485aa5dac62fee7bba2798ca4d6bff64554b8404
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,8a592406c04c2d18d020960bac9fdc750c8078ef..8a592406c04c2d18d020960bac9fdc750c8078ef
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,0f2f7ca45c82ffccd63e6d25430089343e4ffab9..0f2f7ca45c82ffccd63e6d25430089343e4ffab9
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,418f41b7959d8c82dfe3796a1f46f8dc733a3ae5..418f41b7959d8c82dfe3796a1f46f8dc733a3ae5
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,9a7bf21682f8797bc13b4c98bc0928f675138b99..9a7bf21682f8797bc13b4c98bc0928f675138b99
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,2128e0f102ee4c599bae336ff84104d8c3578efc..2128e0f102ee4c599bae336ff84104d8c3578efc
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,18e86f0b7db62c122993ca3f4ba0ba31b51371b9..18e86f0b7db62c122993ca3f4ba0ba31b51371b9
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,a53151d451fc55bb17ac5e2d3cf09a7576d1df01..a53151d451fc55bb17ac5e2d3cf09a7576d1df01
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,79fbca30c19caadf9d5f6ab870f9110e2040fb1a..79fbca30c19caadf9d5f6ab870f9110e2040fb1a
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,bf92fb3e14245fe3271027565448f0db351caa0f..bf92fb3e14245fe3271027565448f0db351caa0f
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,7b450fd86f2ee51137993cfbbbde08dab9146dfa..7b450fd86f2ee51137993cfbbbde08dab9146dfa
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,3a7d37aaf5f2e0527be0c0039bc259c00ba3c910..3a7d37aaf5f2e0527be0c0039bc259c00ba3c910
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,a5dfbbafff8e9fde40e84798c33365354e515bff..a5dfbbafff8e9fde40e84798c33365354e515bff
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,224454ec0dd27214da81a1d5455f08b6bfde23ba..224454ec0dd27214da81a1d5455f08b6bfde23ba
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,0d1ee2077e80b8013bbbb0583238baf1a5aa338b..0d1ee2077e80b8013bbbb0583238baf1a5aa338b
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,752de247500efbf50134a69258466ede09ac4aa6..752de247500efbf50134a69258466ede09ac4aa6
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,8269f049f3bf940337a1860581725eaad8e112e8..8269f049f3bf940337a1860581725eaad8e112e8
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,38e9bd3ed65e5cda45d92adafee7dd0e89a99056..38e9bd3ed65e5cda45d92adafee7dd0e89a99056
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,ba0623b7b5755c29b67653130e1c8c673b8044f6..ba0623b7b5755c29b67653130e1c8c673b8044f6
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,8e4a4d5e376b30f866b2d7a2671662deefd0cbeb..8e4a4d5e376b30f866b2d7a2671662deefd0cbeb
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,3189a133cabca2eac851fe37bf521c54bcfbcc5f..3189a133cabca2eac851fe37bf521c54bcfbcc5f
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,3af9bb6775e6449476506a85ed951048ca196088..3af9bb6775e6449476506a85ed951048ca196088
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,6a754829926e16ecff78787a0f8d1a731d13a59f..6a754829926e16ecff78787a0f8d1a731d13a59f
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,d3c142e2f858aeca9cd6657d41921ae48b6a66dc..d3c142e2f858aeca9cd6657d41921ae48b6a66dc
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,e590f9c3d5ba2041079ccac2c03126224d876b85..e590f9c3d5ba2041079ccac2c03126224d876b85
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,527aa819cea33bcf9edc6b901fa5a411db0cc17b..527aa819cea33bcf9edc6b901fa5a411db0cc17b
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,7c03c1c57ed52cb00d8f19380b986c96206582a2..7c03c1c57ed52cb00d8f19380b986c96206582a2
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,cdc501c2492e8a44459e2a8a43566d6af88cce16..cdc501c2492e8a44459e2a8a43566d6af88cce16
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,719ddfbdca8347bbf0d80b23e45e8a68cad048be..719ddfbdca8347bbf0d80b23e45e8a68cad048be
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,6cde1578daf04ba10841fa7e9038deeda220e46f..6cde1578daf04ba10841fa7e9038deeda220e46f
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,4d4b3e154160f5b6e9d27e1a195b2f8bae55b5e6..4d4b3e154160f5b6e9d27e1a195b2f8bae55b5e6
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,2ec8adda6e4c11b291ff2be4d7de249f84705455..2ec8adda6e4c11b291ff2be4d7de249f84705455
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,772a53b163128078ab01811a8d6f5a292b5a3037..772a53b163128078ab01811a8d6f5a292b5a3037
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,be1c3e472e5795dab0ddec5b10023d97e7185420..be1c3e472e5795dab0ddec5b10023d97e7185420
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,afd1ca507bf3008eca8b577fb84ec770e0e18cc2..afd1ca507bf3008eca8b577fb84ec770e0e18cc2
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,48de6a961ed550b5293354d009c99be71f1c249c..48de6a961ed550b5293354d009c99be71f1c249c
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,feae35de4423451541435bc72848de24d52ce7db..feae35de4423451541435bc72848de24d52ce7db
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,aaca8bf242a2465e711cef566ffd242774cbb350..aaca8bf242a2465e711cef566ffd242774cbb350
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,79f5a7a10c9cdcb2c9c23b12b41afbacdd078f86..79f5a7a10c9cdcb2c9c23b12b41afbacdd078f86
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,b60345e075aa5a41d7d5f5290c0d83b09750bcb1..b60345e075aa5a41d7d5f5290c0d83b09750bcb1
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,d938b0d9cf23ec80530c0ffa4256777daed70375..d938b0d9cf23ec80530c0ffa4256777daed70375
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,fa1b11dbeec6f988ede8ad2d94cb0e433608b911..fa1b11dbeec6f988ede8ad2d94cb0e433608b911
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,ee9913d523f2f1ab6dd687021bec8389f82083d9..ee9913d523f2f1ab6dd687021bec8389f82083d9
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,52c4e092fcc00f7d2554aeec50ec138181eb6906..52c4e092fcc00f7d2554aeec50ec138181eb6906
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,c82f2d629b6233340d6740079080441c5efed23d..c82f2d629b6233340d6740079080441c5efed23d
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,fa63b65035b9d7b323c629ae6e586089e42a718e..fa63b65035b9d7b323c629ae6e586089e42a718e
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,8b2c227fe1fa632645fffdd8d0a03ea87e6c4725..8b2c227fe1fa632645fffdd8d0a03ea87e6c4725
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,ee571897337054754a1ec4f1b573fc8b2cb89169..ee571897337054754a1ec4f1b573fc8b2cb89169
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,cccd8a1fda09677337dae4b6eb078a8b4d37eee8..cccd8a1fda09677337dae4b6eb078a8b4d37eee8
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,f323b5912e1c542e90b72bdb57530edb30c286e8..f323b5912e1c542e90b72bdb57530edb30c286e8
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,ddc6aa0a2a53a1e158419d53e7adb65e439df494..ddc6aa0a2a53a1e158419d53e7adb65e439df494
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,344801f70372579c2acd0ef8519ed967de943c85..344801f70372579c2acd0ef8519ed967de943c85
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,d87a8f7bfa6fe40af2a9a6aea564722b8236a25a..d87a8f7bfa6fe40af2a9a6aea564722b8236a25a
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,dbaeabba74ebf9acfa4e535bbdfaa15cbd64d82e..dbaeabba74ebf9acfa4e535bbdfaa15cbd64d82e
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,84c998b1890b1d14eac97e4d9e83dc2dd0a3254b..84c998b1890b1d14eac97e4d9e83dc2dd0a3254b
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,d096eff9e9d028bbda415db3f3c207d78ffae7e5..d096eff9e9d028bbda415db3f3c207d78ffae7e5
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,4675ab3c121adccf2315b194113b88914164303e..4675ab3c121adccf2315b194113b88914164303e
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,85a68c20599187274ba79ed6e0ec784f38b44fd7..85a68c20599187274ba79ed6e0ec784f38b44fd7
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,b96f1b3778285ec7088bffaa32be8d1b48b7a8d8..b96f1b3778285ec7088bffaa32be8d1b48b7a8d8
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,920edef42a7a856c7fe6975ec64dfdc2ebd4bdcd..920edef42a7a856c7fe6975ec64dfdc2ebd4bdcd
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,6fab6ee4a702b1911062f3eab9b3c7dee05d014e..6fab6ee4a702b1911062f3eab9b3c7dee05d014e
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,fb52ceb79f4d2b9d80e52807f5b7ec5223f62ed8..fb52ceb79f4d2b9d80e52807f5b7ec5223f62ed8
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,855e10d1a44af57bfe1f95fc5c8d17a98d4e256a..855e10d1a44af57bfe1f95fc5c8d17a98d4e256a
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,ee15df1b6d93ce3439605d93b9c588ed1c29aa29..ee15df1b6d93ce3439605d93b9c588ed1c29aa29
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,8a2ef02761f0e3afbdf0ba3e934fc9d8894cf37e..8a2ef02761f0e3afbdf0ba3e934fc9d8894cf37e
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,75cf5bdb4aad2d71753f04efaba53667054c91dd..75cf5bdb4aad2d71753f04efaba53667054c91dd
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,eeb662af18e6cc7c01fcd6ec0d6e5e3cab656494..eeb662af18e6cc7c01fcd6ec0d6e5e3cab656494
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,72f3c6f68c47b95384692094f7104eb6cf362328..72f3c6f68c47b95384692094f7104eb6cf362328
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,c1ab649b6584a6012cbce7f7135e0797217c7579..c1ab649b6584a6012cbce7f7135e0797217c7579
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,80ee0e6b8cabe430757a26a437d3901f8ae97819..80ee0e6b8cabe430757a26a437d3901f8ae97819
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,f5a9a8f564da2f8f46b7cb3c9eac6400fb71a53e..f5a9a8f564da2f8f46b7cb3c9eac6400fb71a53e
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,a225cea325c95f3f0b6385b803a29918794795d8..a225cea325c95f3f0b6385b803a29918794795d8
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,ea9bc951c91e6cd0815e9f39ee93115afeeb9130..ea9bc951c91e6cd0815e9f39ee93115afeeb9130
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,be86e9bf0d4209ae53bd94e2f6e9d7241a9422bc..be86e9bf0d4209ae53bd94e2f6e9d7241a9422bc
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,49f2696dd1344f2ffb2e22ab71467a4a4b200cb6..49f2696dd1344f2ffb2e22ab71467a4a4b200cb6
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,e363bb30ed3103e1d0a53ad95e660778d5ab4947..e363bb30ed3103e1d0a53ad95e660778d5ab4947
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,c1ab649b6584a6012cbce7f7135e0797217c7579..c1ab649b6584a6012cbce7f7135e0797217c7579
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,c09134a31c08836895552d9c56863792c8fa500f..c09134a31c08836895552d9c56863792c8fa500f
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,f5a9a8f564da2f8f46b7cb3c9eac6400fb71a53e..f5a9a8f564da2f8f46b7cb3c9eac6400fb71a53e
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,4fa26cf69a989ada9bf5194e0c20eee0c1df2e47..4fa26cf69a989ada9bf5194e0c20eee0c1df2e47
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,4a8859e729f462644ba9b02afb10909c5253af06..4a8859e729f462644ba9b02afb10909c5253af06
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,1182b7815c067a393b186b5a797e3adef23e23dc..1182b7815c067a393b186b5a797e3adef23e23dc
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,c17e6cdd7479f36a120ed81968ffb8e49688ae84..c17e6cdd7479f36a120ed81968ffb8e49688ae84
mode 000000,100644..100644
--- /dev/null
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..27a6e362cdede345b83b9cc24ec604c54e69e249
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6efcb97c56a76368e8a5fbe512d16b5513c161ce
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4992191eb9e7a41c43209f38dd5c48f07a83b6f9
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9494f2d0c72e6258751e18225967aefd34acf3a5
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..72461343aa2571fb1b9d136196e3252e5dffee72
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,d3815dd80867d176d81d5b64e5fd47ccec200525..d3815dd80867d176d81d5b64e5fd47ccec200525
mode 000000,100644..100644
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7ca7e03b12cff643a21e1a1ca151416d88116039
new file mode 100755 (executable)
Binary files differ
index 0000000000000000000000000000000000000000,3a9716e4e1fbd57ea4f08f9a7f052a37f1ab44a5..3a9716e4e1fbd57ea4f08f9a7f052a37f1ab44a5
mode 000000,100644..100644
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..dd1a5d9aebf32f2f30a1d482ea8b4c3e62d12959
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,63d1810bc94bd7d45a782fea88d18f454cbc64f3..63d1810bc94bd7d45a782fea88d18f454cbc64f3
mode 000000,100644..100644
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0656f81eee834a8a97627ab1196c74c0a4de970c
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d595f6b42f56ea159286004ffad65904d60ccbeb
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..218f075d0c18085e528117a39a51c1c94dea3177
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7ef960bcf244fdb7a8e3d9cbb2ff993106633d52
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..99aaa1d20a32ed1c3736056e4294a1eef1898747
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f10fd560464a494e76fac3b239a6d597d5264933
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a3586004a491e2eb3496625fc4f6dcb3af49aee4
new file mode 100644 (file)
Binary files differ
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..45121805a5bd6d03382d783866c40543a2c8a233
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,76 @@@
++<!--suppress XmlUnboundNsPrefix -->
++<idea-plugin version="2">
++  <id>ru.compscicenter.edide</id>
++  <name>Educational Python IDE</name>
++  <version>1.0</version>
++  <vendor email="support@yourcompany.com" url="http://www.yourcompany.com">YourCompany</vendor>
++
++  <description><![CDATA[
++      Enter short description for your plugin here.<br>
++      <small>most HTML tags may be used</small>
++      ]]></description>
++
++  <change-notes><![CDATA[
++      Add change notes here.<br>
++      <small>most HTML tags may be used</small>
++      ]]>
++  </change-notes>
++
++  <!-- please see http://confluence.jetbrains.net/display/IDEADEV/Build+Number+Ranges for description -->
++  <idea-version since-build="107.105"/>
++
++  <!--depends>com.intellij.modules.python</depends-->
++
++  <!-- please see http://confluence.jetbrains.net/display/IDEADEV/Plugin+Compatibility+with+IntelliJ+Platform+Products
++       on how to target different products -->
++
++  <depends>com.intellij.modules.lang</depends>
++
++  <application-components>
++  </application-components>
++
++  <project-components>
++    <component>
++      <implementation-class>com.jetbrains.python.edu.StudyTaskManager</implementation-class>
++      <interface-class>com.jetbrains.python.edu.StudyTaskManager</interface-class>
++    </component>
++  </project-components>
++
++  <actions>
++    <action id="CheckAction" class="com.jetbrains.python.edu.actions.CheckAction" text="check"
++            description="Runs tests for current tasks" icon="/icons/icon.jpg">
++    </action>
++    <action id="PrevWindowAction" class="com.jetbrains.python.edu.actions.PrevWindowAction" text="PrevWindowAction" description="prev"
++            icon="/icons/prev.png">
++      <add-to-group group-id="MainToolBar" anchor="last"/>
++    </action>
++
++    <action id="NextWindow" class="com.jetbrains.python.edu.actions.NextWindowAction" text="NextWindowAction" description="next"
++            icon="/icons/next.png">
++      <add-to-group group-id="MainToolBar" anchor="last"/>
++    </action>
++    <action id="NextTaskAction" class="com.jetbrains.python.edu.actions.NextTaskAction" text="NextTaskAction" description="Next Task"/>
++    <action id="PreviousTaskAction" class="com.jetbrains.python.edu.actions.PreviousTaskAction" text="PreviousTaskAction"
++            description="Previous Task"/>
++    <action id="RefreshTaskAction" class="com.jetbrains.python.edu.actions.RefreshTaskAction" text="RefreshTaskAction"
++            description="Refresh current task"/>
++    <action id="WatchInputAction" class="com.jetbrains.python.edu.actions.WatchInputAction" text="WatchInputAction"
++            description="watch input"/>
++    <action id="StudyRunAction" class="com.jetbrains.python.edu.actions.StudyRunAction" text="StudyRunAction" description="run your code"/>
++    <action id="ShowHintAction" class="com.jetbrains.python.edu.actions.ShowHintAction" text="Show hint"
++            description="show hint" icon="/icons/showHint.png">
++      <add-to-group group-id="MainToolBar" anchor="last"/>
++    </action>
++  </actions>
++
++  <extensions defaultExtensionNs="com.intellij">
++    <toolWindow id="StudyToolWindow" anchor="right" factoryClass="com.jetbrains.python.edu.ui.StudyToolWindowFactory"
++        icon="/icons/showHint.png" conditionClass="com.jetbrains.python.edu.ui.StudyCondition"/>
++    <fileEditorProvider implementation="com.jetbrains.python.edu.editor.StudyFileEditorProvider"/>
++    <directoryProjectGenerator implementation="com.jetbrains.python.edu.StudyDirectoryProjectGenerator"/>
++    <treeStructureProvider implementation="com.jetbrains.python.edu.projectView.StudyTreeStructureProvider"/>
++    <highlightErrorFilter implementation="com.jetbrains.python.edu.StudyHighlightErrorFilter"/>
++    <applicationService serviceInterface="com.intellij.openapi.fileEditor.impl.EditorEmptyTextPainter"
++        serviceImplementation="com.jetbrains.python.edu.StudyInstructionPainter" overrides="true"/>
++  </extensions>
++</idea-plugin>
index 0000000000000000000000000000000000000000,e1583309fecc086dc05912707a8ac7cf5bdcd63b..38886a04fd691275a0b68fa8a3db77c24d0cc276
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,377 +1,377 @@@
 -package ru.compscicenter.edide;
++package com.jetbrains.python.edu;
+ import com.google.gson.FieldNamingPolicy;
+ import com.google.gson.Gson;
+ import com.google.gson.GsonBuilder;
+ import com.google.gson.JsonParser;
+ import com.intellij.facet.ui.FacetEditorValidator;
+ import com.intellij.facet.ui.FacetValidatorsManager;
+ import com.intellij.facet.ui.ValidationResult;
+ import com.intellij.lang.javascript.boilerplate.GithubDownloadUtil;
+ import com.intellij.openapi.application.PathManager;
+ import com.intellij.openapi.diagnostic.Logger;
+ import com.intellij.openapi.module.Module;
+ import com.intellij.openapi.progress.ProcessCanceledException;
+ import com.intellij.openapi.project.Project;
+ import com.intellij.openapi.vfs.VirtualFile;
+ import com.intellij.openapi.vfs.VirtualFileManager;
+ import com.intellij.platform.DirectoryProjectGenerator;
+ import com.intellij.platform.templates.github.GeneratorException;
+ import com.intellij.platform.templates.github.ZipUtil;
+ import com.jetbrains.python.newProject.PythonProjectGenerator;
+ import icons.StudyIcons;
+ import org.jetbrains.annotations.Nls;
+ import org.jetbrains.annotations.NotNull;
+ import org.jetbrains.annotations.Nullable;
 -import ru.compscicenter.edide.course.Course;
 -import ru.compscicenter.edide.course.CourseInfo;
 -import ru.compscicenter.edide.ui.StudyNewProjectPanel;
++import com.jetbrains.python.edu.course.Course;
++import com.jetbrains.python.edu.course.CourseInfo;
++import com.jetbrains.python.edu.ui.StudyNewProjectPanel;
+ import javax.swing.*;
+ import java.io.*;
+ import java.util.HashMap;
+ import java.util.Map;
+ import java.util.regex.Matcher;
+ import java.util.regex.Pattern;
+ public class StudyDirectoryProjectGenerator extends PythonProjectGenerator implements DirectoryProjectGenerator {
+   private static final Logger LOG = Logger.getInstance(StudyDirectoryProjectGenerator.class.getName());
+   private static final String REPO_URL = "https://github.com/medvector/initial-python-course/archive/master.zip";
+   private static final String USER_NAME = "medvector";
+   private static final String COURSE_META_FILE = "course.json";
+   private static final String COURSE_NAME_ATTRIBUTE = "name";
+   private static final Pattern CACHE_PATTERN = Pattern.compile("(name=(.*)) (path=(.*course.json)) (author=(.*)) (description=(.*))");
+   private static final String REPOSITORY_NAME = "initial-python-course";
+   public static final String AUTHOR_ATTRIBUTE = "author";
+   private final File myCoursesDir = new File(PathManager.getLibPath(), "courses");
+   private static final String CACHE_NAME = "courseNames.txt";
+   private Map<CourseInfo, File> myCourses = new HashMap<CourseInfo, File>();
+   private File mySelectedCourseFile;
+   private Project myProject;
+   public ValidationResult myValidationResult = new ValidationResult("selected course is not valid");
+   @Nls
+   @NotNull
+   @Override
+   public String getName() {
+     return "Study project";
+   }
+   public void setCourses(Map<CourseInfo, File> courses) {
+     myCourses = courses;
+   }
+   /**
+    * Finds selected course in courses by name.
+    *
+    * @param courseName name of selected course
+    */
+   public void setSelectedCourse(@NotNull CourseInfo courseName) {
+     File courseFile = myCourses.get(courseName);
+     if (courseFile == null) {
+       LOG.error("invalid course in list");
+     }
+     mySelectedCourseFile = courseFile;
+   }
+   /**
+    * Adds course to courses specified in params
+    *
+    * @param courseDir must be directory containing course file
+    * @return added course name or null if course is invalid
+    */
+   @Nullable
+   private CourseInfo addCourse(Map<CourseInfo, File> courses, File courseDir) {
+     if (courseDir.isDirectory()) {
+       File[] courseFiles = courseDir.listFiles(new FilenameFilter() {
+         @Override
+         public boolean accept(File dir, String name) {
+           return name.equals(COURSE_META_FILE);
+         }
+       });
+       if (courseFiles.length != 1) {
+         LOG.info("User tried to add course with more than one or without course files");
+         return null;
+       }
+       File courseFile = courseFiles[0];
+       CourseInfo courseInfo = getCourseInfo(courseFile);
+       if (courseInfo != null) {
+         courses.put(courseInfo, courseFile);
+       }
+       return courseInfo;
+     }
+     return null;
+   }
+   /**
+    * Adds course from zip archive to courses
+    *
+    * @return added course name or null if course is invalid
+    */
+   @Nullable
+   public CourseInfo addLocalCourse(String zipFilePath) {
+     File file = new File(zipFilePath);
+     try {
+       String fileName = file.getName();
+       String unzippedName = fileName.substring(0, fileName.indexOf("."));
+       File courseDir = new File(myCoursesDir, unzippedName);
+       ZipUtil.unzip(null, courseDir, file, null, null, true);
+       CourseInfo courseName = addCourse(myCourses, courseDir);
+       flushCache();
+       return courseName;
+     }
+     catch (IOException e) {
+       LOG.error("Failed to unzip course archive");
+       LOG.error(e);
+     }
+     return null;
+   }
+   @Nullable
+   @Override
+   public Object showGenerationSettings(VirtualFile baseDir) throws ProcessCanceledException {
+     return null;
+   }
+   @Nullable
+   @Override
+   public Icon getLogo() {
+     return StudyIcons.Playground;
+   }
+   @Override
+   public void generateProject(@NotNull final Project project, @NotNull final VirtualFile baseDir,
+                               @Nullable Object settings, @NotNull Module module) {
+     myProject = project;
+     Reader reader = null;
+     try {
+       reader = new InputStreamReader(new FileInputStream(mySelectedCourseFile));
+       Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
+       Course course = gson.fromJson(reader, Course.class);
+       course.init(false);
+       course.create(baseDir, new File(mySelectedCourseFile.getParent()));
+       course.setResourcePath(mySelectedCourseFile.getAbsolutePath());
+       VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
+       StudyTaskManager.getInstance(project).setCourse(course);
+     }
+     catch (FileNotFoundException e) {
+       e.printStackTrace();
+     }
+     finally {
+       StudyUtils.closeSilently(reader);
+     }
+   }
+   /**
 -   * Downloads courses from {@link ru.compscicenter.edide.StudyDirectoryProjectGenerator#REPO_URL}
 -   * and unzips them into {@link ru.compscicenter.edide.StudyDirectoryProjectGenerator#myCoursesDir}
++   * Downloads courses from {@link com.jetbrains.python.edu.StudyDirectoryProjectGenerator#REPO_URL}
++   * and unzips them into {@link com.jetbrains.python.edu.StudyDirectoryProjectGenerator#myCoursesDir}
+    */
+   public void downloadAndUnzip(boolean needProgressBar) {
+     File outputFile = new File(PathManager.getLibPath(), "courses.zip");
+     try {
+       if (!needProgressBar) {
+         GithubDownloadUtil.downloadAtomically(null, REPO_URL,
+                                               outputFile, USER_NAME, REPOSITORY_NAME);
+       }
+       else {
+         GithubDownloadUtil.downloadContentToFileWithProgressSynchronously(myProject, REPO_URL, "downloading courses", outputFile, USER_NAME,
+                                                                           REPOSITORY_NAME, false);
+       }
+       if (outputFile.exists()) {
+         ZipUtil.unzip(null, myCoursesDir, outputFile, null, null, true);
+         if (!outputFile.delete()) {
+           LOG.error("Failed to delete", outputFile.getName());
+         }
+         File[] files = myCoursesDir.listFiles();
+         if (files != null) {
+           for (File file : files) {
+             String fileName = file.getName();
+             if (StudyUtils.isZip(fileName)) {
+               ZipUtil.unzip(null, new File(myCoursesDir, fileName.substring(0, fileName.indexOf("."))), file, null, null, true);
+               if (!file.delete()) {
+                 LOG.error("Failed to delete", fileName);
+               }
+             }
+           }
+         }
+       }
+     }
+     catch (IOException e) {
+       e.printStackTrace();
+     }
+     catch (GeneratorException e) {
+       e.printStackTrace();
+     }
+   }
+   public Map<CourseInfo, File> getLoadedCourses() {
+     return myCourses;
+   }
+   /**
 -   * Parses courses located in {@link ru.compscicenter.edide.StudyDirectoryProjectGenerator#myCoursesDir}
 -   * to {@link ru.compscicenter.edide.StudyDirectoryProjectGenerator#myCourses}
++   * Parses courses located in {@link com.jetbrains.python.edu.StudyDirectoryProjectGenerator#myCoursesDir}
++   * to {@link com.jetbrains.python.edu.StudyDirectoryProjectGenerator#myCourses}
+    *
+    * @return map with course names and course files location
+    */
+   public Map<CourseInfo, File> loadCourses() {
+     Map<CourseInfo, File> courses = new HashMap<CourseInfo, File>();
+     if (myCoursesDir.exists()) {
+       File[] courseDirs = myCoursesDir.listFiles(new FileFilter() {
+         @Override
+         public boolean accept(File pathname) {
+           return pathname.isDirectory();
+         }
+       });
+       for (File courseDir : courseDirs) {
+         addCourse(courses, courseDir);
+       }
+     }
+     return courses;
+   }
+   /**
+    * Parses course json meta file and finds course name
+    *
+    * @return information about course or null if course file is invalid
+    */
+   @Nullable
+   private CourseInfo getCourseInfo(File courseFile) {
+     CourseInfo courseInfo = null;
+     BufferedReader reader = null;
+     try {
+       if (courseFile.getName().equals(COURSE_META_FILE)) {
+         reader = new BufferedReader(new InputStreamReader(new FileInputStream(courseFile)));
+         com.google.gson.stream.JsonReader r = new com.google.gson.stream.JsonReader(reader);
+         JsonParser parser = new JsonParser();
+         com.google.gson.JsonElement el = parser.parse(r);
+         String courseName = el.getAsJsonObject().get(COURSE_NAME_ATTRIBUTE).getAsString();
+         String courseAuthor = el.getAsJsonObject().get(AUTHOR_ATTRIBUTE).getAsString();
+         String courseDescription = el.getAsJsonObject().get("description").getAsString();
+         courseInfo = new CourseInfo(courseName, courseAuthor, courseDescription);
+       }
+     }
+     catch (FileNotFoundException e) {
+       e.printStackTrace();
+     }
+     finally {
+       StudyUtils.closeSilently(reader);
+     }
+     return courseInfo;
+   }
+   @NotNull
+   @Override
+   public ValidationResult validate(@NotNull String s) {
+     return myValidationResult;
+   }
+   public void setValidationResult(ValidationResult validationResult) {
+     myValidationResult = validationResult;
+   }
+   /**
+    * @return courses from memory or from cash file or parses course directory
+    */
+   public Map<CourseInfo, File> getCourses() {
+     if (!myCourses.isEmpty()) {
+       return myCourses;
+     }
+     if (myCoursesDir.exists()) {
+       File cacheFile = new File(myCoursesDir, CACHE_NAME);
+       if (cacheFile.exists()) {
+         myCourses = getCoursesFromCache(cacheFile);
+         if (!myCourses.isEmpty()) {
+           return myCourses;
+         }
+       }
+       myCourses = loadCourses();
+       if (!myCourses.isEmpty()) {
+         return myCourses;
+       }
+     }
+     downloadAndUnzip(false);
+     myCourses = loadCourses();
+     flushCache();
+     return myCourses;
+   }
+   /**
 -   * Writes courses to cash file {@link ru.compscicenter.edide.StudyDirectoryProjectGenerator#CACHE_NAME}
++   * Writes courses to cash file {@link com.jetbrains.python.edu.StudyDirectoryProjectGenerator#CACHE_NAME}
+    */
+   public void flushCache() {
+     File cashFile = new File(myCoursesDir, CACHE_NAME);
+     PrintWriter writer = null;
+     try {
+       writer = new PrintWriter(cashFile);
+       for (Map.Entry<CourseInfo, File> course : myCourses.entrySet()) {
+         CourseInfo courseInfo = course.getKey();
+         String line = String
+           .format("name=%s path=%s author=%s description=%s", courseInfo.getName(), course.getValue(), courseInfo.getAuthor(),
+                   courseInfo.getDescription());
+         writer.println(line);
+       }
+     }
+     catch (FileNotFoundException e) {
+       e.printStackTrace();
+     }
+     finally {
+       StudyUtils.closeSilently(writer);
+     }
+   }
+   /**
 -   * Loads courses from {@link ru.compscicenter.edide.StudyDirectoryProjectGenerator#CACHE_NAME} file
++   * Loads courses from {@link com.jetbrains.python.edu.StudyDirectoryProjectGenerator#CACHE_NAME} file
+    *
+    * @return map of course names and course files
+    */
+   private Map<CourseInfo, File> getCoursesFromCache(File cashFile) {
+     Map<CourseInfo, File> coursesFromCash = new HashMap<CourseInfo, File>();
+     try {
+       BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(cashFile)));
+       String line;
+       while ((line = reader.readLine()) != null) {
+         Matcher matcher = CACHE_PATTERN.matcher(line);
+         if (matcher.matches()) {
+           String courseName = matcher.group(2);
+           File file = new File(matcher.group(4));
+           String author = matcher.group(6);
+           String description = matcher.group(8);
+           CourseInfo courseInfo = new CourseInfo(courseName, author, description);
+           if (file.exists()) {
+             coursesFromCash.put(courseInfo, file);
+           }
+         }
+       }
+     }
+     catch (FileNotFoundException e) {
+       e.printStackTrace();
+     }
+     catch (IOException e) {
+       e.printStackTrace();
+     }
+     return coursesFromCash;
+   }
+   @Nullable
+   @Override
+   public JPanel extendBasePanel() throws ProcessCanceledException {
+     StudyNewProjectPanel settingsPanel = new StudyNewProjectPanel(this);
+     settingsPanel.registerValidators(new FacetValidatorsManager() {
+       public void registerValidator(FacetEditorValidator validator, JComponent... componentsToWatch) {
+         throw new UnsupportedOperationException();
+       }
+       public void validate() {
+         fireStateChanged();
+       }
+     });
+     return settingsPanel.getContentPanel();
+   }
+ }
index 0000000000000000000000000000000000000000,f6bbec140891232a4ce2ebaeb1a56d33cdee2770..0d26168a3ebcaad1c4de791da6106c7f712013ed
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,66 +1,66 @@@
 -package ru.compscicenter.edide;
++package com.jetbrains.python.edu;
+ import com.intellij.openapi.editor.Document;
+ import com.intellij.openapi.editor.LogicalPosition;
+ import com.intellij.openapi.editor.event.DocumentAdapter;
+ import com.intellij.openapi.editor.event.DocumentEvent;
+ import com.intellij.openapi.editor.impl.event.DocumentEventImpl;
 -import ru.compscicenter.edide.course.TaskFile;
 -import ru.compscicenter.edide.course.TaskWindow;
++import com.jetbrains.python.edu.course.TaskFile;
++import com.jetbrains.python.edu.course.TaskWindow;
+ /**
+  * author: liana
+  * data: 7/16/14.
+  * Listens changes in study files and updates
+  * coordinates of all the windows in current task file
+  */
+ public class StudyDocumentListener extends DocumentAdapter {
+   private final TaskFile myTaskFile;
+   private int oldLine;
+   private int oldLineStartOffset;
+   private TaskWindow myTaskWindow;
+   public StudyDocumentListener(TaskFile taskFile) {
+     myTaskFile = taskFile;
+   }
+   //remembering old end before document change because of problems
+   // with fragments containing "\n"
+   @Override
+   public void beforeDocumentChange(DocumentEvent e) {
+     int offset = e.getOffset();
+     int oldEnd = offset + e.getOldLength();
+     Document document = e.getDocument();
+     oldLine = document.getLineNumber(oldEnd);
+     oldLineStartOffset = document.getLineStartOffset(oldLine);
+     int line = document.getLineNumber(offset);
+     int offsetInLine = offset - document.getLineStartOffset(line);
+     LogicalPosition pos = new LogicalPosition(line, offsetInLine);
+     myTaskWindow = myTaskFile.getTaskWindow(document, pos);
+   }
+   @Override
+   public void documentChanged(DocumentEvent e) {
+     if (e instanceof DocumentEventImpl) {
+       DocumentEventImpl event = (DocumentEventImpl)e;
+       Document document = e.getDocument();
+       int offset = e.getOffset();
+       int change = event.getNewLength() - event.getOldLength();
+       if (myTaskWindow != null) {
+         int newLength = myTaskWindow.getLength() + change;
+         myTaskWindow.setLength(newLength);
+       }
+       int newEnd = offset + event.getNewLength();
+       int newLine = document.getLineNumber(newEnd);
+       int lineChange = newLine - oldLine;
+       myTaskFile.incrementLines(oldLine + 1, lineChange);
+       int newEndOffsetInLine = offset + e.getNewLength() - document.getLineStartOffset(newLine);
+       int oldEndOffsetInLine = offset + e.getOldLength() - oldLineStartOffset;
+       myTaskFile.updateLine(lineChange, oldLine, newEndOffsetInLine, oldEndOffsetInLine);
+       System.out.println();
+     }
+   }
+ }
index 0000000000000000000000000000000000000000,d9a88613e327efad8f75a0fe04c3fce92616b85c..92c1a39c12ce9112297e3835c7ab512dea8ac71e
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,102 +1,102 @@@
 -package ru.compscicenter.edide;
++package com.jetbrains.python.edu;
+ import com.intellij.openapi.application.ApplicationManager;
+ import com.intellij.openapi.editor.Document;
+ import com.intellij.openapi.editor.Editor;
+ import com.intellij.openapi.editor.LogicalPosition;
+ import com.intellij.openapi.editor.event.EditorFactoryEvent;
+ import com.intellij.openapi.editor.event.EditorFactoryListener;
+ import com.intellij.openapi.editor.event.EditorMouseAdapter;
+ import com.intellij.openapi.editor.event.EditorMouseEvent;
+ import com.intellij.openapi.fileEditor.FileDocumentManager;
+ import com.intellij.openapi.project.Project;
+ import com.intellij.openapi.vfs.VirtualFile;
+ import org.jetbrains.annotations.NotNull;
 -import ru.compscicenter.edide.course.StudyStatus;
 -import ru.compscicenter.edide.course.TaskFile;
 -import ru.compscicenter.edide.course.TaskWindow;
 -import ru.compscicenter.edide.editor.StudyEditor;
++import com.jetbrains.python.edu.course.StudyStatus;
++import com.jetbrains.python.edu.course.TaskFile;
++import com.jetbrains.python.edu.course.TaskWindow;
++import com.jetbrains.python.edu.editor.StudyEditor;
+ import java.awt.*;
+ /**
+  * User: lia
+  */
+ class StudyEditorFactoryListener implements EditorFactoryListener {
+   /**
+    * draws selected task window if there is one located in mouse position
+    */
+   private class WindowSelectionListener extends EditorMouseAdapter {
+     private final TaskFile myTaskFile;
+     WindowSelectionListener(TaskFile taskFile) {
+       myTaskFile = taskFile;
+     }
+     @Override
+     public void mouseClicked(EditorMouseEvent e) {
+       Editor editor = e.getEditor();
+       Point point = e.getMouseEvent().getPoint();
+       LogicalPosition pos = editor.xyToLogicalPosition(point);
+       TaskWindow taskWindow = myTaskFile.getTaskWindow(editor.getDocument(), pos);
+       if (taskWindow != null) {
+         myTaskFile.setSelectedTaskWindow(taskWindow);
+         taskWindow.draw(editor, taskWindow.getStatus() != StudyStatus.Solved, true);
+       }
+       else {
+         myTaskFile.drawAllWindows(editor);
+       }
+     }
+   }
+   @Override
+   public void editorCreated(@NotNull final EditorFactoryEvent event) {
+     final Editor editor = event.getEditor();
+     final Project project = editor.getProject();
+     if (project == null) {
+       return;
+     }
+     ApplicationManager.getApplication().invokeLater(
+       new Runnable() {
+         @Override
+         public void run() {
+           ApplicationManager.getApplication().runWriteAction(new Runnable() {
+             @Override
+             public void run() {
+               Document document = editor.getDocument();
+               VirtualFile openedFile = FileDocumentManager.getInstance().getFile(document);
+               if (openedFile != null) {
+                 StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
+                 TaskFile taskFile = taskManager.getTaskFile(openedFile);
+                 if (taskFile != null) {
+                   editor.addEditorMouseListener(new WindowSelectionListener(taskFile));
+                   StudyDocumentListener listener = new StudyDocumentListener(taskFile);
+                   StudyEditor.addDocumentListener(document, listener);
+                   document.addDocumentListener(listener);
+                   taskFile.drawAllWindows(editor);
+                 }
+               }
+             }
+           });
+         }
+       }
+     );
+   }
+   @Override
+   public void editorReleased(@NotNull EditorFactoryEvent event) {
+     Editor editor = event.getEditor();
+     Document document = editor.getDocument();
+     StudyDocumentListener listener = StudyEditor.getListener(document);
+     if (listener != null) {
+       document.removeDocumentListener(listener);
+       StudyEditor.removeListener(document);
+     }
+     editor.getMarkupModel().removeAllHighlighters();
+     editor.getSelectionModel().removeSelection();
+   }
+ }
index 0000000000000000000000000000000000000000,14dcd9c6fb87c97e80423dd23c12d5eafb212250..1377128ed4172b44acb4b5c3de9a23d648dfa349
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,23 +1,23 @@@
 -package ru.compscicenter.edide;
++package com.jetbrains.python.edu;
+ import com.intellij.codeInsight.highlighting.HighlightErrorFilter;
+ import com.intellij.openapi.project.Project;
+ import com.intellij.openapi.vfs.VirtualFile;
+ import com.intellij.psi.PsiErrorElement;
+ import org.jetbrains.annotations.NotNull;
 -import ru.compscicenter.edide.course.TaskFile;
++import com.jetbrains.python.edu.course.TaskFile;
+ /**
+  * author: liana
+  * data: 7/23/14.
+  */
+ public class StudyHighlightErrorFilter extends HighlightErrorFilter {
+   @Override
+   public boolean shouldHighlightErrorElement(@NotNull final PsiErrorElement element) {
+     VirtualFile file = element.getContainingFile().getVirtualFile();
+     Project project = element.getProject();
+     StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
+     TaskFile taskFile = taskManager.getTaskFile(file);
+     return taskFile == null;
+   }
+ }
index 0000000000000000000000000000000000000000,9ab95de3be4616005d31faabc9b0d63d0487d4aa..7e8e33fb65d4b2646017e42f368bc8d2a81a17a1
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,46 +1,46 @@@
 -package ru.compscicenter.edide;
++package com.jetbrains.python.edu;
+ import com.intellij.openapi.fileEditor.impl.EditorEmptyTextPainter;
+ import com.intellij.openapi.fileEditor.impl.EditorsSplitters;
+ import com.intellij.openapi.util.Couple;
+ import com.intellij.ui.Gray;
+ import com.intellij.ui.JBColor;
+ import com.intellij.util.PairFunction;
+ import com.intellij.util.ui.GraphicsUtil;
+ import com.intellij.util.ui.UIUtil;
 -import ru.compscicenter.edide.ui.StudyCondition;
++import com.jetbrains.python.edu.ui.StudyCondition;
+ import java.awt.*;
+ /**
+  * author: liana
+  * data: 7/29/14.
+  */
+ public class StudyInstructionPainter extends EditorEmptyTextPainter {
+   @Override
+   public void paintEmptyText(final EditorsSplitters splitters, Graphics g) {
+     if (!StudyCondition.VALUE) {
+       super.paintEmptyText(splitters, g);
+       return;
+     }
+     boolean isDarkBackground = UIUtil.isUnderDarcula();
+     UIUtil.applyRenderingHints(g);
+     GraphicsUtil.setupAntialiasing(g, true, false);
+     g.setColor(new JBColor(isDarkBackground ? Gray._230 : Gray._80, Gray._160));
+     g.setFont(UIUtil.getLabelFont().deriveFont(isDarkBackground ? 24f : 20f));
+     UIUtil.TextPainter painter = new UIUtil.TextPainter().withLineSpacing(1.5f);
+     painter.withShadow(true, new JBColor(Gray._200.withAlpha(100), Gray._0.withAlpha(255)));
+     painter.appendLine("Welcome to PyCharm Educational Edition").underlined(new JBColor(Gray._150, Gray._180));
+     painter.appendLine("Learn Python programming in your favorite IDE").smaller();
+     painter.appendLine("Navigate between windows with alt < >").smaller().withBullet();
+     painter.draw(g, new PairFunction<Integer, Integer, Couple<Integer>>() {
+       @Override
+       public Couple<Integer> fun(Integer width, Integer height) {
+         Dimension s = splitters.getSize();
+         return Couple.of((s.width - width) / 2, (s.height - height) / 2);
+       }
+     });
+   }
+ }
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..38f1c2ff2cdeaa26c3c92a67e2bbe1c6f60af427
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,5 @@@
++package com.jetbrains.python.edu;
++
++public interface StudyResourceManger {
++  String USER_TESTER = "user_tester.py";
++}
index 0000000000000000000000000000000000000000,a7f2c3ef06fa1e681e149559893a554d863bc646..d3e0f33ca56273bd0d0703e96a1e623765e5f9b2
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,283 +1,283 @@@
 -package ru.compscicenter.edide;
++package com.jetbrains.python.edu;
+ import com.intellij.ide.ui.UISettings;
+ import com.intellij.openapi.actionSystem.*;
+ import com.intellij.openapi.actionSystem.ex.AnActionListener;
+ import com.intellij.openapi.application.ApplicationManager;
+ import com.intellij.openapi.components.*;
+ import com.intellij.openapi.editor.EditorFactory;
+ import com.intellij.openapi.keymap.Keymap;
+ import com.intellij.openapi.keymap.KeymapManager;
+ import com.intellij.openapi.project.DumbAware;
+ import com.intellij.openapi.project.DumbAwareRunnable;
+ import com.intellij.openapi.project.Project;
+ import com.intellij.openapi.vfs.VirtualFile;
+ import com.intellij.openapi.vfs.VirtualFileAdapter;
+ import com.intellij.openapi.vfs.VirtualFileEvent;
+ import com.intellij.openapi.vfs.VirtualFileManager;
+ import com.intellij.openapi.wm.ToolWindow;
+ import com.intellij.openapi.wm.ToolWindowAnchor;
+ import com.intellij.openapi.wm.ToolWindowManager;
+ import com.intellij.util.xmlb.XmlSerializer;
+ import icons.StudyIcons;
+ import org.jdom.Element;
+ import org.jetbrains.annotations.NotNull;
+ import org.jetbrains.annotations.Nullable;
 -import ru.compscicenter.edide.actions.NextWindowAction;
 -import ru.compscicenter.edide.actions.PrevWindowAction;
 -import ru.compscicenter.edide.actions.ShowHintAction;
 -import ru.compscicenter.edide.course.Course;
 -import ru.compscicenter.edide.course.Lesson;
 -import ru.compscicenter.edide.course.Task;
 -import ru.compscicenter.edide.course.TaskFile;
 -import ru.compscicenter.edide.ui.StudyCondition;
 -import ru.compscicenter.edide.ui.StudyToolWindowFactory;
++import com.jetbrains.python.edu.actions.NextWindowAction;
++import com.jetbrains.python.edu.actions.PrevWindowAction;
++import com.jetbrains.python.edu.actions.ShowHintAction;
++import com.jetbrains.python.edu.course.Course;
++import com.jetbrains.python.edu.course.Lesson;
++import com.jetbrains.python.edu.course.Task;
++import com.jetbrains.python.edu.course.TaskFile;
++import com.jetbrains.python.edu.ui.StudyCondition;
++import com.jetbrains.python.edu.ui.StudyToolWindowFactory;
+ import javax.swing.*;
+ import java.lang.reflect.Method;
+ import java.util.HashMap;
+ import java.util.List;
+ import java.util.Map;
+ /**
+  * Implementation of class which contains all the information
+  * about study in context of current project
+  */
+ @State(
+   name = "StudySettings",
+   storages = {
+     @Storage(
+       id = "others",
+       file = "$PROJECT_CONFIG_DIR$/study_project.xml",
+       scheme = StorageScheme.DIRECTORY_BASED
+     )}
+ )
+ public class StudyTaskManager implements ProjectComponent, PersistentStateComponent<Element>, DumbAware {
+   public static final String COURSE_ELEMENT = "courseElement";
+   private static Map<String, StudyTaskManager> myTaskManagers = new HashMap<String, StudyTaskManager>();
+   private static Map<String, String> myDeletedShortcuts = new HashMap<String, String>();
+   private final Project myProject;
+   private Course myCourse;
+   private FileCreatedListener myListener;
+   public void setCourse(Course course) {
+     myCourse = course;
+   }
+   private StudyTaskManager(@NotNull final Project project) {
+     myTaskManagers.put(project.getBasePath(), this);
+     myProject = project;
+   }
+   @Nullable
+   public Course getCourse() {
+     return myCourse;
+   }
+   @Nullable
+   @Override
+   public Element getState() {
+     Element el = new Element("taskManager");
+     if (myCourse != null) {
+       Element courseElement = new Element(COURSE_ELEMENT);
+       XmlSerializer.serializeInto(myCourse, courseElement);
+       el.addContent(courseElement);
+     }
+     return el;
+   }
+   @Override
+   public void loadState(Element el) {
+     myCourse = XmlSerializer.deserialize(el.getChild(COURSE_ELEMENT), Course.class);
+     if (myCourse != null) {
+       myCourse.init(true);
+     }
+   }
+   @Override
+   public void projectOpened() {
+     ApplicationManager.getApplication().invokeLater(new DumbAwareRunnable() {
+       @Override
+       public void run() {
+         ApplicationManager.getApplication().runWriteAction(new DumbAwareRunnable() {
+           @Override
+           public void run() {
+             if (myCourse != null) {
+               UISettings.getInstance().HIDE_TOOL_STRIPES = false;
+               UISettings.getInstance().fireUISettingsChanged();
+               ToolWindowManager toolWindowManager = ToolWindowManager.getInstance(myProject);
+               String toolWindowId = StudyToolWindowFactory.STUDY_TOOL_WINDOW;
+               //TODO:decide smth with tool window position
+               try {
+                 Method method = toolWindowManager.getClass().getDeclaredMethod("registerToolWindow", String.class,
+                                                                                JComponent.class,
+                                                                                ToolWindowAnchor.class,
+                                                                                boolean.class, boolean.class, boolean.class);
+                 method.setAccessible(true);
+                 method.invoke(toolWindowManager, toolWindowId, null, ToolWindowAnchor.LEFT, true, true, true);
+               }
+               catch (Exception e) {
+                 toolWindowManager
+                   .registerToolWindow(toolWindowId, true, ToolWindowAnchor.RIGHT, myProject, true);
+               }
+               final ToolWindow studyToolWindow = toolWindowManager.getToolWindow(toolWindowId);
+               if (studyToolWindow != null) {
+                 StudyUtils.updateStudyToolWindow(myProject);
+                 studyToolWindow.setIcon(StudyIcons.ShortcutReminder);
+                 studyToolWindow.show(null);
+               }
+               addShortcut(NextWindowAction.SHORTCUT, NextWindowAction.ACTION_ID);
+               addShortcut(PrevWindowAction.SHORTCUT, PrevWindowAction.ACTION_ID);
+               addShortcut(ShowHintAction.SHORTCUT, ShowHintAction.ACTION_ID);
+               addShortcut(NextWindowAction.SHORTCUT2, NextWindowAction.ACTION_ID);
+             }
+           }
+         });
+       }
+     });
+   }
+   private void addShortcut(@NotNull final String shortcutString, @NotNull final String actionIdString) {
+     Keymap keymap = KeymapManager.getInstance().getActiveKeymap();
+     Shortcut studyActionShortcut = new KeyboardShortcut(KeyStroke.getKeyStroke(shortcutString), null);
+     String[] actionsIds = keymap.getActionIds(studyActionShortcut);
+     for (String actionId : actionsIds) {
+       myDeletedShortcuts.put(actionId, shortcutString);
+       keymap.removeShortcut(actionId, studyActionShortcut);
+     }
+     keymap.addShortcut(actionIdString, studyActionShortcut);
+   }
+   @Override
+   public void projectClosed() {
+     StudyCondition.VALUE = false;
+     if (myCourse != null) {
+       ToolWindowManager.getInstance(myProject).getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW).getContentManager()
+         .removeAllContents(false);
+       if (!myDeletedShortcuts.isEmpty()) {
+         for (Map.Entry<String, String> shortcut : myDeletedShortcuts.entrySet()) {
+           Keymap keymap = KeymapManager.getInstance().getActiveKeymap();
+           Shortcut actionShortcut = new KeyboardShortcut(KeyStroke.getKeyStroke(shortcut.getValue()), null);
+           keymap.addShortcut(shortcut.getKey(), actionShortcut);
+         }
+       }
+     }
+   }
+   @Override
+   public void initComponent() {
+     EditorFactory.getInstance().addEditorFactoryListener(new StudyEditorFactoryListener(), myProject);
+     ActionManager.getInstance().addAnActionListener(new AnActionListener() {
+       @Override
+       public void beforeActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) {
+         AnAction[] newGroupActions = ((ActionGroup)ActionManager.getInstance().getAction("NewGroup")).getChildren(null);
+         for (AnAction newAction : newGroupActions) {
+           if (newAction == action) {
+             myListener =  new FileCreatedListener();
+             VirtualFileManager.getInstance().addVirtualFileListener(myListener);
+             break;
+           }
+         }
+       }
+       @Override
+       public void afterActionPerformed(AnAction action, DataContext dataContext, AnActionEvent event) {
+         AnAction[] newGroupActions = ((ActionGroup)ActionManager.getInstance().getAction("NewGroup")).getChildren(null);
+         for (AnAction newAction : newGroupActions) {
+           if (newAction == action) {
+             VirtualFileManager.getInstance().removeVirtualFileListener(myListener);
+           }
+         }
+       }
+       @Override
+       public void beforeEditorTyping(char c, DataContext dataContext) {
+       }
+     });
+   }
+   @Override
+   public void disposeComponent() {
+   }
+   @NotNull
+   @Override
+   public String getComponentName() {
+     return "StudyTaskManager";
+   }
+   public static StudyTaskManager getInstance(@NotNull final Project project) {
+     StudyTaskManager item = myTaskManagers.get(project.getBasePath());
+     return item != null ? item : new StudyTaskManager(project);
+   }
+   @Nullable
+   public TaskFile getTaskFile(@NotNull final VirtualFile file) {
+     if (myCourse == null) {
+       return null;
+     }
+     VirtualFile taskDir = file.getParent();
+     if (taskDir != null) {
+       String taskDirName = taskDir.getName();
+       if (taskDirName.contains(Task.TASK_DIR)) {
+         VirtualFile lessonDir = taskDir.getParent();
+         if (lessonDir != null) {
+           String lessonDirName = lessonDir.getName();
+           int lessonIndex = StudyUtils.getIndex(lessonDirName, Lesson.LESSON_DIR);
+           List<Lesson> lessons = myCourse.getLessons();
+           if (!StudyUtils.indexIsValid(lessonIndex, lessons)) {
+             return null;
+           }
+           Lesson lesson = lessons.get(lessonIndex);
+           int taskIndex = StudyUtils.getIndex(taskDirName, Task.TASK_DIR);
+           List<Task> tasks = lesson.getTaskList();
+           if (!StudyUtils.indexIsValid(taskIndex, tasks)) {
+             return null;
+           }
+           Task task = tasks.get(taskIndex);
+           return task.getFile(file.getName());
+         }
+       }
+     }
+     return null;
+   }
+   class FileCreatedListener extends VirtualFileAdapter {
+     @Override
+     public void fileCreated(@NotNull VirtualFileEvent event) {
+       VirtualFile createdFile = event.getFile();
+       VirtualFile taskDir = createdFile.getParent();
+       String taskLogicalName = Task.TASK_DIR;
+       if (taskDir != null && taskDir.getName().contains(taskLogicalName)) {
+         int taskIndex = StudyUtils.getIndex(taskDir.getName(), taskLogicalName);
+         VirtualFile lessonDir = taskDir.getParent();
+         String lessonLogicalName = Lesson.LESSON_DIR;
+         if (lessonDir != null && lessonDir.getName().contains(lessonLogicalName)) {
+           int lessonIndex = StudyUtils.getIndex(lessonDir.getName(), lessonLogicalName);
+           if (myCourse != null) {
+             List<Lesson> lessons = myCourse.getLessons();
+             if (StudyUtils.indexIsValid(lessonIndex, lessons)) {
+               Lesson lesson = lessons.get(lessonIndex);
+               List<Task> tasks = lesson.getTaskList();
+               if (StudyUtils.indexIsValid(taskIndex, tasks)) {
+                 Task task = tasks.get(taskIndex);
+                 TaskFile taskFile = new TaskFile();
+                 taskFile.init(task, false);
+                 taskFile.setUserCreated(true);
+                 task.getTaskFiles().put(createdFile.getName(), taskFile);
+               }
+             }
+           }
+         }
+       }
+     }
+   }
+ }
index 0000000000000000000000000000000000000000,cb53eeb04b876ae72d15d3fe4834fd0453e40316..cc4cd810993327a594430604c390f808849fd480
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,148 +1,148 @@@
 -package ru.compscicenter.edide;
++package com.jetbrains.python.edu;
+ import com.intellij.ide.SaveAndSyncHandlerImpl;
+ import com.intellij.openapi.actionSystem.AnActionEvent;
+ import com.intellij.openapi.actionSystem.Presentation;
+ import com.intellij.openapi.editor.Document;
+ import com.intellij.openapi.fileEditor.FileDocumentManager;
+ import com.intellij.openapi.fileEditor.FileEditor;
+ import com.intellij.openapi.fileEditor.FileEditorManager;
+ import com.intellij.openapi.project.Project;
+ import com.intellij.openapi.util.TextRange;
+ import com.intellij.openapi.vfs.VirtualFile;
+ import com.intellij.openapi.vfs.VirtualFileManager;
+ import com.intellij.openapi.wm.ToolWindowManager;
+ import com.intellij.util.ui.UIUtil;
+ import org.jetbrains.annotations.NotNull;
 -import ru.compscicenter.edide.course.TaskFile;
 -import ru.compscicenter.edide.course.TaskWindow;
 -import ru.compscicenter.edide.editor.StudyEditor;
 -import ru.compscicenter.edide.ui.StudyToolWindowFactory;
++import com.jetbrains.python.edu.course.TaskFile;
++import com.jetbrains.python.edu.course.TaskWindow;
++import com.jetbrains.python.edu.editor.StudyEditor;
++import com.jetbrains.python.edu.ui.StudyToolWindowFactory;
+ import java.io.*;
+ import java.util.Collection;
+ /**
+  * author: liana
+  * data: 7/15/14.
+  */
+ public class StudyUtils {
+   public static void closeSilently(Closeable stream) {
+     if (stream != null) {
+       try {
+         stream.close();
+       }
+       catch (IOException e) {
+         // close silently
+       }
+     }
+   }
+   public static boolean isZip(String fileName) {
+     return fileName.contains(".zip");
+   }
+   public static <T> T getFirst(Iterable<T> container) {
+     return container.iterator().next();
+   }
+   public static boolean indexIsValid(int index, Collection collection) {
+     int size = collection.size();
+     return index >= 0 && index < size;
+   }
+   public static String getFileText(String parentDir, String fileName, boolean wrapHTML) {
+     File inputFile = parentDir !=null ? new File(parentDir, fileName) : new File(fileName);
+     StringBuilder taskText = new StringBuilder();
+     BufferedReader reader = null;
+     try {
+       reader = new BufferedReader(new InputStreamReader(new FileInputStream(inputFile)));
+       String line;
+       while ((line = reader.readLine()) != null) {
+         taskText.append(line).append("\n");
+         if (wrapHTML) {
+           taskText.append("<br>");
+         }
+       }
+       return wrapHTML ? UIUtil.toHtml(taskText.toString()) : taskText.toString();
+     }
+     catch (IOException e) {
+       e.printStackTrace();
+     }
+     finally {
+       StudyUtils.closeSilently(reader);
+     }
+     return null;
+   }
+   public static void updateAction(AnActionEvent e) {
+     Presentation presentation = e.getPresentation();
+     presentation.setEnabled(false);
+     Project project = e.getProject();
+     if (project != null) {
+       FileEditor[] editors = FileEditorManager.getInstance(project).getAllEditors();
+       for (FileEditor editor : editors) {
+         if (editor instanceof StudyEditor) {
+           presentation.setEnabled(true);
+         }
+       }
+     }
+   }
+   public static void updateStudyToolWindow(Project project) {
+     ToolWindowManager.getInstance(project).getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW).getContentManager().removeAllContents(false);
+     StudyToolWindowFactory factory =  new StudyToolWindowFactory();
+     factory.createToolWindowContent(project, ToolWindowManager.getInstance(project).getToolWindow(StudyToolWindowFactory.STUDY_TOOL_WINDOW));
+   }
+   public  static void synchronize() {
+     FileDocumentManager.getInstance().saveAllDocuments();
+     SaveAndSyncHandlerImpl.refreshOpenFiles();
+     VirtualFileManager.getInstance().refreshWithoutFileWatcher(true);
+   }
+   /**
+    * Gets number index in directory names like "task1", "lesson2"
+    *
+    * @param fullName    full name of directory
+    * @param logicalName part of name without index
+    * @return index of object
+    */
+   public static int getIndex(@NotNull final String fullName, @NotNull final String logicalName) {
+     if (!fullName.contains(logicalName)) {
+       throw new IllegalArgumentException();
+     }
+     return Integer.parseInt(fullName.substring(logicalName.length())) - 1;
+   }
+   public static VirtualFile flushWindows(Document document, TaskFile taskFile, VirtualFile file) {
+     VirtualFile taskDir = file.getParent();
+     VirtualFile file_windows = null;
+     if (taskDir != null) {
+       String name = file.getNameWithoutExtension() + "_windows";
+       PrintWriter printWriter = null;
+       try {
+         file_windows = taskDir.createChildData(taskFile, name);
+         printWriter = new PrintWriter(new FileOutputStream(file_windows.getPath()));
+         for (TaskWindow taskWindow : taskFile.getTaskWindows()) {
+           if (!taskWindow.isValid(document)) {
+             continue;
+           }
+           int start = taskWindow.getRealStartOffset(document);
+           String windowDescription = document.getText(new TextRange(start, start + taskWindow.getLength()));
+           printWriter.println("#study_plugin_window = " + windowDescription);
+         }
+       }
+       catch (IOException e) {
+         e.printStackTrace();
+       }
+       finally {
+         closeSilently(printWriter);
+         StudyUtils.synchronize();
+       }
+     }
+     return file_windows;
+   }
+ }
index 0000000000000000000000000000000000000000,e5340e45c9ed75ca064052f95ceb9c9520963071..0ab9f129960aa746948cecc7cde361d50b67354b
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,283 +1,283 @@@
 -package ru.compscicenter.edide.actions;
++package com.jetbrains.python.edu.actions;
+ import com.intellij.execution.ExecutionException;
+ import com.intellij.execution.configurations.GeneralCommandLine;
+ import com.intellij.ide.projectView.ProjectView;
+ import com.intellij.openapi.actionSystem.ActionManager;
+ import com.intellij.openapi.actionSystem.AnActionEvent;
+ import com.intellij.openapi.application.ApplicationManager;
+ import com.intellij.openapi.command.CommandProcessor;
+ import com.intellij.openapi.diagnostic.Logger;
+ import com.intellij.openapi.editor.Document;
+ import com.intellij.openapi.editor.Editor;
+ import com.intellij.openapi.fileEditor.FileDocumentManager;
+ import com.intellij.openapi.module.ModuleManager;
+ import com.intellij.openapi.project.DumbAwareAction;
+ import com.intellij.openapi.project.Project;
+ import com.intellij.openapi.projectRoots.Sdk;
+ import com.intellij.openapi.ui.popup.Balloon;
+ import com.intellij.openapi.ui.popup.BalloonBuilder;
+ import com.intellij.openapi.ui.popup.JBPopupFactory;
+ import com.intellij.openapi.util.TextRange;
+ import com.intellij.openapi.util.io.FileUtil;
+ import com.intellij.openapi.vfs.VirtualFile;
+ import com.intellij.ui.JBColor;
+ import com.jetbrains.python.sdk.PythonSdkType;
+ import org.jetbrains.annotations.NotNull;
 -import ru.compscicenter.edide.StudyDocumentListener;
 -import ru.compscicenter.edide.StudyTaskManager;
 -import ru.compscicenter.edide.StudyUtils;
 -import ru.compscicenter.edide.course.*;
 -import ru.compscicenter.edide.editor.StudyEditor;
++import com.jetbrains.python.edu.StudyDocumentListener;
++import com.jetbrains.python.edu.StudyTaskManager;
++import com.jetbrains.python.edu.StudyUtils;
++import com.jetbrains.python.edu.course.*;
++import com.jetbrains.python.edu.editor.StudyEditor;
+ import javax.swing.*;
+ import java.awt.*;
+ import java.io.*;
+ import java.util.Map;
+ public class CheckAction extends DumbAwareAction {
+   private static final Logger LOG = Logger.getInstance(CheckAction.class.getName());
+   class StudyTestRunner {
+     public static final String TEST_OK = "#study_plugin test OK";
+     private static final String TEST_FAILED = "#study_plugin FAILED + ";
+     private final Task myTask;
+     private final VirtualFile myTaskDir;
+     StudyTestRunner(Task task, VirtualFile taskDir) {
+       myTask = task;
+       myTaskDir = taskDir;
+     }
+     Process launchTests(Project project, String executablePath) throws ExecutionException {
+       Sdk sdk = PythonSdkType.findPythonSdk(ModuleManager.getInstance(project).getModules()[0]);
+       File testRunner = new File(myTaskDir.getPath(), myTask.getTestFile());
+       GeneralCommandLine commandLine = new GeneralCommandLine();
+       commandLine.setWorkDirectory(myTaskDir.getPath());
+       final Map<String, String> env = commandLine.getEnvironment();
+       final VirtualFile courseDir = project.getBaseDir();
+       if (courseDir != null)
+         env.put("PYTHONPATH", courseDir.getPath());
+       if (sdk != null) {
+         String pythonPath = sdk.getHomePath();
+         if (pythonPath != null) {
+           commandLine.setExePath(pythonPath);
+           commandLine.addParameter(testRunner.getPath());
+           final Course course = StudyTaskManager.getInstance(project).getCourse();
+           assert course != null;
+           commandLine.addParameter(new File(course.getResourcePath()).getParent());
+           commandLine.addParameter(executablePath);
+           return commandLine.createProcess();
+         }
+       }
+       return null;
+     }
+     String getPassedTests(Process p) {
+       InputStream testOutput = p.getInputStream();
+       BufferedReader testOutputReader = new BufferedReader(new InputStreamReader(testOutput));
+       String line;
+       try {
+         while ((line = testOutputReader.readLine()) != null) {
+           if (line.contains(TEST_FAILED)) {
+              return line.substring(TEST_FAILED.length(), line.length());
+           }
+         }
+       }
+       catch (IOException e) {
+         LOG.error(e);
+       }
+       finally {
+         StudyUtils.closeSilently(testOutputReader);
+       }
+       return StudyTestRunner.TEST_OK;
+     }
+   }
+   public void check(@NotNull final Project project) {
+     ApplicationManager.getApplication().runWriteAction(new Runnable() {
+       @Override
+       public void run() {
+         CommandProcessor.getInstance().executeCommand(project, new Runnable() {
+           @Override
+           public void run() {
+             final Editor selectedEditor = StudyEditor.getSelectedEditor(project);
+             if (selectedEditor != null) {
+               final FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
+               final VirtualFile openedFile = fileDocumentManager.getFile(selectedEditor.getDocument());
+               if (openedFile != null) {
+                 StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
+                 final TaskFile selectedTaskFile = taskManager.getTaskFile(openedFile);
+                 if (selectedTaskFile != null) {
+                   StudyUtils.flushWindows(selectedEditor.getDocument(),selectedTaskFile, openedFile);
+                   FileDocumentManager.getInstance().saveAllDocuments();
+                   final VirtualFile taskDir = openedFile.getParent();
+                   Task currentTask = selectedTaskFile.getTask();
+                   StudyRunAction runAction = (StudyRunAction)ActionManager.getInstance().getAction(StudyRunAction.ACTION_ID);
+                   if (runAction != null) {
+                     runAction.run(project);
+                   }
+                   final StudyTestRunner testRunner = new StudyTestRunner(currentTask, taskDir);
+                   Process testProcess = null;
+                   try {
+                     testProcess = testRunner.launchTests(project, openedFile.getPath());
+                   }
+                   catch (ExecutionException e) {
+                     LOG.error(e);
+                   }
+                   if (testProcess != null) {
+                     String failedMessage = testRunner.getPassedTests(testProcess);
+                     if (failedMessage.equals(StudyTestRunner.TEST_OK)) {
+                       currentTask.setStatus(StudyStatus.Solved);
+                       StudyUtils.updateStudyToolWindow(project);
+                       selectedTaskFile.drawAllWindows(selectedEditor);
+                       ProjectView.getInstance(project).refresh();
+                       createTestResultPopUp("Congratulations!", JBColor.GREEN, project);
+                       return;
+                     }
+                     final TaskFile taskFileCopy = new TaskFile();
+                     final VirtualFile copyWithAnswers = getCopyWithAnswers(taskDir, openedFile, selectedTaskFile, taskFileCopy);
+                     for (final TaskWindow taskWindow : taskFileCopy.getTaskWindows()) {
+                       if (!taskWindow.isValid(selectedEditor.getDocument())) {
+                         continue;
+                       }
+                       check(project, taskWindow, copyWithAnswers, taskFileCopy, selectedTaskFile, selectedEditor.getDocument(), testRunner, openedFile);
+                     }
+                     try {
+                       copyWithAnswers.delete(this);
+                     }
+                     catch (IOException e) {
+                       LOG.error(e);
+                     }
+                     selectedTaskFile.drawAllWindows(selectedEditor);
+                     createTestResultPopUp(failedMessage, JBColor.RED, project);
+                   }
+                 }
+               }
+             }
+           }
+         }, null, null);
+       }
+     });
+   }
+   private void check(Project project,
+                      TaskWindow taskWindow,
+                      VirtualFile answerFile,
+                      TaskFile answerTaskFile,
+                      TaskFile usersTaskFile,
+                      Document usersDocument,
+                      StudyTestRunner testRunner,
+                      VirtualFile openedFile) {
+     try {
+       VirtualFile windowCopy = answerFile.copy(this, answerFile.getParent(), "window" + taskWindow.getIndex() + ".py");
+       final FileDocumentManager documentManager = FileDocumentManager.getInstance();
+       final Document windowDocument = documentManager.getDocument(windowCopy);
+       if (windowDocument != null) {
+         StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
+         Course course = taskManager.getCourse();
+         Task task = usersTaskFile.getTask();
+         int taskNum = task.getIndex() + 1;
+         int lessonNum = task.getLesson().getIndex() + 1;
+         assert course != null;
+         String pathToResource = FileUtil.join(new File(course.getResourcePath()).getParent(), Lesson.LESSON_DIR + lessonNum,  Task.TASK_DIR + taskNum);
+         File resourceFile = new File(pathToResource, windowCopy.getName());
+         FileUtil.copy(new File(pathToResource, openedFile.getName()), resourceFile);
+         TaskFile windowTaskFile = new TaskFile();
+         TaskFile.copy(answerTaskFile, windowTaskFile);
+         StudyDocumentListener listener = new StudyDocumentListener(windowTaskFile);
+         windowDocument.addDocumentListener(listener);
+         int start = taskWindow.getRealStartOffset(windowDocument);
+         int end = start + taskWindow.getLength();
+         TaskWindow userTaskWindow = usersTaskFile.getTaskWindows().get(taskWindow.getIndex());
+         int userStart = userTaskWindow.getRealStartOffset(usersDocument);
+         int userEnd = userStart + userTaskWindow.getLength();
+         String text = usersDocument.getText(new TextRange(userStart, userEnd));
+         windowDocument.replaceString(start, end, text);
+         ApplicationManager.getApplication().runWriteAction(new Runnable() {
+           @Override
+           public void run() {
+             documentManager.saveDocument(windowDocument);
+           }
+         });
+         VirtualFile fileWindows = StudyUtils.flushWindows(windowDocument, windowTaskFile, windowCopy);
+         Process smartTestProcess = testRunner.launchTests(project, windowCopy.getPath());
+         boolean res = testRunner.getPassedTests(smartTestProcess).equals(StudyTestRunner.TEST_OK);
+         userTaskWindow.setStatus(res ? StudyStatus.Solved : StudyStatus.Failed);
+         windowCopy.delete(this);
+         fileWindows.delete(this);
+         if (!resourceFile.delete()) {
+           LOG.error("failed to delete", resourceFile.getPath());
+         }
+       }
+     }
+     catch (IOException e) {
+       LOG.error(e);
+     }
+     catch (ExecutionException e) {
+       e.printStackTrace();
+     }
+   }
+   private VirtualFile getCopyWithAnswers(final VirtualFile taskDir,
+                                          final VirtualFile file,
+                                          final TaskFile source,
+                                          TaskFile target) {
+     VirtualFile copy = null;
+     try {
+       copy = file.copy(this, taskDir, "answers.py");
+       final FileDocumentManager documentManager = FileDocumentManager.getInstance();
+       final Document document = documentManager.getDocument(copy);
+       if (document != null) {
+         TaskFile.copy(source, target);
+         StudyDocumentListener listener = new StudyDocumentListener(target);
+         document.addDocumentListener(listener);
+         for (TaskWindow taskWindow : target.getTaskWindows()) {
+           if (!taskWindow.isValid(document)) {
+             continue;
+           }
+           final int start = taskWindow.getRealStartOffset(document);
+           final int end = start + taskWindow.getLength();
+           final String text = taskWindow.getPossibleAnswer();
+           document.replaceString(start, end, text);
+         }
+         ApplicationManager.getApplication().runWriteAction(new Runnable() {
+           @Override
+           public void run() {
+             documentManager.saveDocument(document);
+           }
+         });
+       }
+     }
+     catch (IOException e) {
+       LOG.error(e);
+     }
+     return copy;
+   }
+   private void createTestResultPopUp(final String text, Color color, @NotNull final Project project) {
+     BalloonBuilder balloonBuilder =
+       JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(text, null, color, null);
+     Balloon balloon = balloonBuilder.createBalloon();
+     StudyEditor studyEditor = StudyEditor.getSelectedStudyEditor(project);
+     assert studyEditor != null;
+     JButton checkButton = studyEditor.getCheckButton();
+     balloon.showInCenterOf(checkButton);
+   }
+   @Override
+   public void actionPerformed(AnActionEvent e) {
+     Project project = e.getProject();
+     if (project != null) {
+       check(project);
+     }
+   }
+ }
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..51fe494552bae53079b2b76f962318f0e05fbc92
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,24 @@@
++package com.jetbrains.python.edu.actions;
++
++import com.jetbrains.python.edu.editor.StudyEditor;
++import com.jetbrains.python.edu.course.Task;
++
++import javax.swing.*;
++
++public class NextTaskAction extends TaskNavigationAction {
++
++  @Override
++  protected JButton getButton(StudyEditor selectedStudyEditor) {
++    return selectedStudyEditor.getNextTaskButton();
++  }
++
++  @Override
++  protected String getNavigationFinishedMessage() {
++    return "It's the last task";
++  }
++
++  @Override
++  protected Task getTargetTask(Task sourceTask) {
++    return sourceTask.next();
++  }
++}
index 0000000000000000000000000000000000000000,7f91b90ec5cbf6e88cc09529ca1155c96f535588..95abf163a7798899fe857d35400c47356269a46e
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,57 +1,57 @@@
 -package ru.compscicenter.edide.actions;
++package com.jetbrains.python.edu.actions;
+ import com.intellij.openapi.actionSystem.AnActionEvent;
+ import com.intellij.openapi.editor.Editor;
+ import com.intellij.openapi.fileEditor.FileDocumentManager;
+ import com.intellij.openapi.project.DumbAwareAction;
+ import com.intellij.openapi.project.Project;
+ import com.intellij.openapi.vfs.VirtualFile;
 -import ru.compscicenter.edide.StudyTaskManager;
 -import ru.compscicenter.edide.StudyUtils;
 -import ru.compscicenter.edide.course.StudyStatus;
 -import ru.compscicenter.edide.course.TaskFile;
 -import ru.compscicenter.edide.course.TaskWindow;
 -import ru.compscicenter.edide.editor.StudyEditor;
++import com.jetbrains.python.edu.StudyTaskManager;
++import com.jetbrains.python.edu.StudyUtils;
++import com.jetbrains.python.edu.course.StudyStatus;
++import com.jetbrains.python.edu.course.TaskFile;
++import com.jetbrains.python.edu.course.TaskWindow;
++import com.jetbrains.python.edu.editor.StudyEditor;
+ /**
+  * move caret to next task window
+  */
+ public class NextWindowAction extends DumbAwareAction {
+   public static final String ACTION_ID = "NextWindow";
+   public static final String SHORTCUT = "ctrl pressed PERIOD";
+   public static final String SHORTCUT2 = "ctrl pressed ENTER";
+   public void actionPerformed(AnActionEvent e) {
+     Project project = e.getProject();
+     if (project != null) {
+       Editor selectedEditor = StudyEditor.getSelectedEditor(project);
+       if (selectedEditor != null) {
+         FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
+         VirtualFile openedFile = fileDocumentManager.getFile(selectedEditor.getDocument());
+         if (openedFile != null) {
+           StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
+           TaskFile selectedTaskFile = taskManager.getTaskFile(openedFile);
+           if (selectedTaskFile != null) {
+             TaskWindow selectedTaskWindow = selectedTaskFile.getSelectedTaskWindow();
+             boolean ifDraw = false;
+             for (TaskWindow taskWindow : selectedTaskFile.getTaskWindows()) {
+               if (ifDraw) {
+                 selectedTaskFile.setSelectedTaskWindow(taskWindow);
+                 taskWindow.draw(selectedEditor, taskWindow.getStatus() != StudyStatus.Solved, true);
+                 return;
+               }
+               if (taskWindow == selectedTaskWindow) {
+                 ifDraw = true;
+               }
+             }
+           }
+         }
+       }
+     }
+   }
+   @Override
+   public void update(AnActionEvent e) {
+     StudyUtils.updateAction(e);
+   }
+ }
index 0000000000000000000000000000000000000000,1080dc871739e6d247c94076a0a680bfab59b3aa..60a0d606884877f7e0403ffc23c0c003a2956649
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,56 +1,56 @@@
 -package ru.compscicenter.edide.actions;
++package com.jetbrains.python.edu.actions;
+ import com.intellij.openapi.actionSystem.AnActionEvent;
+ import com.intellij.openapi.editor.Editor;
+ import com.intellij.openapi.fileEditor.FileDocumentManager;
+ import com.intellij.openapi.project.DumbAwareAction;
+ import com.intellij.openapi.project.Project;
+ import com.intellij.openapi.vfs.VirtualFile;
 -import ru.compscicenter.edide.StudyTaskManager;
 -import ru.compscicenter.edide.StudyUtils;
 -import ru.compscicenter.edide.course.StudyStatus;
 -import ru.compscicenter.edide.course.TaskFile;
 -import ru.compscicenter.edide.course.TaskWindow;
 -import ru.compscicenter.edide.editor.StudyEditor;
++import com.jetbrains.python.edu.StudyTaskManager;
++import com.jetbrains.python.edu.StudyUtils;
++import com.jetbrains.python.edu.course.StudyStatus;
++import com.jetbrains.python.edu.course.TaskFile;
++import com.jetbrains.python.edu.course.TaskWindow;
++import com.jetbrains.python.edu.editor.StudyEditor;
+ /**
+  * author: liana
+  * data: 6/30/14.
+  */
+ public class PrevWindowAction extends DumbAwareAction {
+   public static final String ACTION_ID = "PrevWindowAction";
+   public static final String SHORTCUT = "ctrl pressed COMMA";
+   public void actionPerformed(AnActionEvent e) {
+     Project project = e.getProject();
+     assert project != null;
+     Editor selectedEditor = StudyEditor.getSelectedEditor(project);
+     if (selectedEditor != null) {
+       FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
+       VirtualFile openedFile = fileDocumentManager.getFile(selectedEditor.getDocument());
+       if (openedFile != null) {
+         StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
+         TaskFile selectedTaskFile = taskManager.getTaskFile(openedFile);
+         if (selectedTaskFile != null) {
+           TaskWindow selectedTaskWindow = selectedTaskFile.getSelectedTaskWindow();
+           TaskWindow prev = null;
+           for (TaskWindow taskWindow : selectedTaskFile.getTaskWindows()) {
+             if (taskWindow == selectedTaskWindow) {
+               break;
+             }
+             prev = taskWindow;
+           }
+           if (prev != null) {
+             selectedTaskFile.setSelectedTaskWindow(prev);
+             prev.draw(selectedEditor, prev.getStatus() != StudyStatus.Solved, true);
+           }
+         }
+       }
+     }
+   }
+   @Override
+   public void update(AnActionEvent e) {
+     StudyUtils.updateAction(e);
+   }
+ }
index 0000000000000000000000000000000000000000,08cb1e70db2552d36ede5525f56699649b6d5784..4474656f4feae9e10c7bd016237eb933c7224c95
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,25 +1,25 @@@
 -package ru.compscicenter.edide.actions;
++package com.jetbrains.python.edu.actions;
 -import ru.compscicenter.edide.editor.StudyEditor;
 -import ru.compscicenter.edide.course.Task;
++import com.jetbrains.python.edu.editor.StudyEditor;
++import com.jetbrains.python.edu.course.Task;
+ import javax.swing.*;
+ public class PreviousTaskAction extends TaskNavigationAction {
+   @Override
+   protected JButton getButton(StudyEditor selectedStudyEditor) {
+     return selectedStudyEditor.getPrevTaskButton();
+   }
+   @Override
+   protected String getNavigationFinishedMessage() {
+     return "It's already the first task";
+   }
+   @Override
+   protected Task getTargetTask(Task sourceTask) {
+     return sourceTask.prev();
+   }
+ }
index 0000000000000000000000000000000000000000,032170be7d58d72992d401704011ac52c7e146e8..bf521e7d1ad37ae73544c9b099e2030d5c6adb68
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,132 +1,132 @@@
 -package ru.compscicenter.edide.actions;
++package com.jetbrains.python.edu.actions;
+ import com.intellij.ide.projectView.ProjectView;
+ import com.intellij.openapi.actionSystem.AnActionEvent;
+ import com.intellij.openapi.application.ApplicationManager;
+ import com.intellij.openapi.command.CommandProcessor;
+ import com.intellij.openapi.editor.Document;
+ import com.intellij.openapi.editor.Editor;
+ import com.intellij.openapi.fileEditor.FileDocumentManager;
+ import com.intellij.openapi.project.DumbAwareAction;
+ import com.intellij.openapi.project.Project;
+ import com.intellij.openapi.ui.MessageType;
+ import com.intellij.openapi.ui.popup.Balloon;
+ import com.intellij.openapi.ui.popup.BalloonBuilder;
+ import com.intellij.openapi.ui.popup.JBPopupFactory;
+ import com.intellij.openapi.vfs.VirtualFile;
 -import ru.compscicenter.edide.StudyDocumentListener;
 -import ru.compscicenter.edide.StudyTaskManager;
 -import ru.compscicenter.edide.StudyUtils;
 -import ru.compscicenter.edide.course.*;
 -import ru.compscicenter.edide.editor.StudyEditor;
++import com.jetbrains.python.edu.StudyDocumentListener;
++import com.jetbrains.python.edu.StudyTaskManager;
++import com.jetbrains.python.edu.StudyUtils;
++import com.jetbrains.python.edu.course.*;
++import com.jetbrains.python.edu.editor.StudyEditor;
+ import java.io.*;
+ /**
+  * author: liana
+  * data: 7/8/14.
+  */
+ public class RefreshTaskAction extends DumbAwareAction {
+   public void refresh(final Project project) {
+     ApplicationManager.getApplication().invokeLater(new Runnable() {
+       @Override
+       public void run() {
+         ApplicationManager.getApplication().runWriteAction(new Runnable() {
+           @Override
+           public void run() {
+             CommandProcessor.getInstance().executeCommand(project, new Runnable() {
+               @Override
+               public void run() {
+                 Editor editor = StudyEditor.getSelectedEditor(project);
+                 assert editor != null;
+                 Document document = editor.getDocument();
+                 StudyDocumentListener listener = StudyEditor.getListener(document);
+                 if (listener != null) {
+                   document.removeDocumentListener(listener);
+                 }
+                 int lineCount = document.getLineCount();
+                 if (lineCount != 0) {
+                   document.deleteString(0, document.getLineEndOffset(lineCount - 1));
+                 }
+                 StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
+                 Course course = taskManager.getCourse();
+                 assert course != null;
+                 File resourceFile = new File(course.getResourcePath());
+                 File resourceRoot = resourceFile.getParentFile();
+                 FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
+                 VirtualFile openedFile = fileDocumentManager.getFile(document);
+                 assert openedFile != null;
+                 TaskFile selectedTaskFile = taskManager.getTaskFile(openedFile);
+                 assert selectedTaskFile != null;
+                 Task currentTask = selectedTaskFile.getTask();
+                 String lessonDir = Lesson.LESSON_DIR + String.valueOf(currentTask.getLesson().getIndex() + 1);
+                 String taskDir = Task.TASK_DIR + String.valueOf(currentTask.getIndex() + 1);
+                   File pattern = new File(new File(new File(resourceRoot, lessonDir), taskDir), openedFile.getName());
+                   BufferedReader reader = null;
+                   try {
+                     reader = new BufferedReader(new InputStreamReader(new FileInputStream(pattern)));
+                     String line;
+                     StringBuilder patternText = new StringBuilder();
+                     while ((line = reader.readLine()) != null) {
+                       patternText.append(line);
+                       patternText.append("\n");
+                     }
+                     int patternLength = patternText.length();
+                     if (patternText.charAt(patternLength - 1) == '\n') {
+                       patternText.delete(patternLength - 1, patternLength);
+                     }
+                     document.setText(patternText);
+                     StudyStatus oldStatus = currentTask.getStatus();
+                     LessonInfo lessonInfo = currentTask.getLesson().getLessonInfo();
+                     if (oldStatus == StudyStatus.Failed) {
+                       lessonInfo.setTaskFailed(lessonInfo.getTaskFailed() - 1);
+                     }
+                     if (oldStatus == StudyStatus.Solved) {
+                       lessonInfo.setTaskSolved(lessonInfo.getTaskSolved() - 1);
+                     }
+                     lessonInfo.setTaskUnchecked(lessonInfo.getTaskUnchecked() + 1);
+                     StudyUtils.updateStudyToolWindow(project);
+                     for (TaskWindow taskWindow : selectedTaskFile.getTaskWindows()) {
+                       taskWindow.reset();
+                     }
+                     ProjectView.getInstance(project).refresh();
+                     if (listener != null) {
+                       document.addDocumentListener(listener);
+                     }
+                     selectedTaskFile.drawAllWindows(editor);
+                     BalloonBuilder balloonBuilder =
+                       JBPopupFactory.getInstance().createHtmlTextBalloonBuilder("You can now start again", MessageType.INFO, null);
+                     Balloon balloon = balloonBuilder.createBalloon();
+                     StudyEditor selectedStudyEditor = StudyEditor.getSelectedStudyEditor(project);
+                     assert selectedStudyEditor != null;
+                     balloon.showInCenterOf(selectedStudyEditor.getRefreshButton());
+                   }
+                   catch (FileNotFoundException e1) {
+                     e1.printStackTrace();
+                   }
+                   catch (IOException e1) {
+                     e1.printStackTrace();
+                   }
+                   finally {
+                     if (reader != null) {
+                       try {
+                         reader.close();
+                       }
+                       catch (IOException e) {
+                         e.printStackTrace();
+                       }
+                     }
+                   }
+               }
+             }, null, null);
+           }
+         });
+       }
+     });
+   }
+   public void actionPerformed(AnActionEvent e) {
+     refresh(e.getProject());
+   }
+ }
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1c2744b0b2738c416d588a2dfe196955b7b793b5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,90 @@@
++package com.jetbrains.python.edu.actions;
++
++import com.intellij.codeInsight.documentation.DocumentationComponent;
++import com.intellij.codeInsight.documentation.DocumentationManager;
++import com.intellij.openapi.actionSystem.AnActionEvent;
++import com.intellij.openapi.editor.Editor;
++import com.intellij.openapi.editor.LogicalPosition;
++import com.intellij.openapi.fileEditor.FileDocumentManager;
++import com.intellij.openapi.project.DumbAwareAction;
++import com.intellij.openapi.project.Project;
++import com.intellij.openapi.ui.popup.JBPopup;
++import com.intellij.openapi.ui.popup.JBPopupFactory;
++import com.intellij.openapi.vfs.VirtualFile;
++import com.intellij.psi.PsiElement;
++import com.intellij.psi.PsiFile;
++import com.intellij.psi.PsiManager;
++import com.jetbrains.python.edu.StudyTaskManager;
++import com.jetbrains.python.edu.StudyUtils;
++import com.jetbrains.python.edu.course.Course;
++import com.jetbrains.python.edu.course.TaskFile;
++import com.jetbrains.python.edu.course.TaskWindow;
++import com.jetbrains.python.edu.editor.StudyEditor;
++
++import java.io.File;
++
++public class ShowHintAction extends DumbAwareAction {
++  public static final String ACTION_ID = "ShowHintAction";
++  public static final String SHORTCUT = "ctrl pressed 7";
++
++  public void actionPerformed(AnActionEvent e) {
++    Project project = e.getProject();
++    if (project != null) {
++      DocumentationManager documentationManager = DocumentationManager.getInstance(project);
++      DocumentationComponent component = new DocumentationComponent(documentationManager);
++      Editor selectedEditor = StudyEditor.getSelectedEditor(project);
++      FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
++      assert selectedEditor != null;
++      VirtualFile openedFile = fileDocumentManager.getFile(selectedEditor.getDocument());
++      if (openedFile != null) {
++        StudyTaskManager taskManager = StudyTaskManager.getInstance(e.getProject());
++        TaskFile taskFile = taskManager.getTaskFile(openedFile);
++        if (taskFile != null) {
++          PsiFile file = PsiManager.getInstance(project).findFile(openedFile);
++          if (file != null) {
++            LogicalPosition pos = selectedEditor.getCaretModel().getLogicalPosition();
++            TaskWindow taskWindow = taskFile.getTaskWindow(selectedEditor.getDocument(), pos);
++            if (taskWindow != null) {
++              String hint = taskWindow.getHint();
++              if (hint == null) {
++                return;
++              }
++              Course course = taskManager.getCourse();
++              if (course != null) {
++                File resourceFile = new File(course.getResourcePath());
++                File resourceRoot = resourceFile.getParentFile();
++                if (resourceRoot != null && resourceRoot.exists()) {
++                  File hintsDir = new File(resourceRoot, Course.HINTS_DIR);
++                  if (hintsDir.exists()) {
++                    String hintText = StudyUtils.getFileText(hintsDir.getAbsolutePath(), hint, true);
++                    if (hintText != null) {
++                      int offset = selectedEditor.getDocument().getLineStartOffset(pos.line) + pos.column;
++                      PsiElement element = file.findElementAt(offset);
++                      if (element != null) {
++                        component.setData(element, hintText, true, null);
++                        final JBPopup popup =
++                          JBPopupFactory.getInstance().createComponentPopupBuilder(component, component)
++                            .setDimensionServiceKey(project, DocumentationManager.JAVADOC_LOCATION_AND_SIZE, false)
++                            .setResizable(true)
++                            .setMovable(true)
++                            .setRequestFocus(true)
++                            .createPopup();
++                        component.setHint(popup);
++                        popup.showInBestPositionFor(selectedEditor);
++                      }
++                    }
++                  }
++                }
++              }
++            }
++          }
++        }
++      }
++    }
++  }
++
++  @Override
++  public void update(AnActionEvent e) {
++    StudyUtils.updateAction(e);
++  }
++}
index 0000000000000000000000000000000000000000,76777e96f9b9cfe84159141a15c6a82a7c8df686..6b2ba9bc325390b5bad52ba954a3e7c9d2e35950
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,82 +1,82 @@@
 -package ru.compscicenter.edide.actions;
++package com.jetbrains.python.edu.actions;
+ import com.intellij.execution.ExecutionException;
+ import com.intellij.execution.RunContentExecutor;
+ import com.intellij.execution.configurations.GeneralCommandLine;
+ import com.intellij.execution.process.OSProcessHandler;
+ import com.intellij.execution.process.ProcessHandler;
+ import com.intellij.openapi.actionSystem.AnActionEvent;
+ import com.intellij.openapi.editor.Editor;
+ import com.intellij.openapi.fileEditor.FileDocumentManager;
+ import com.intellij.openapi.module.ModuleManager;
+ import com.intellij.openapi.project.DumbAwareAction;
+ import com.intellij.openapi.project.Project;
+ import com.intellij.openapi.projectRoots.Sdk;
+ import com.intellij.openapi.vfs.VirtualFile;
+ import com.jetbrains.python.sdk.PythonSdkType;
 -import ru.compscicenter.edide.StudyResourceManger;
 -import ru.compscicenter.edide.StudyTaskManager;
 -import ru.compscicenter.edide.course.Task;
 -import ru.compscicenter.edide.course.TaskFile;
 -import ru.compscicenter.edide.editor.StudyEditor;
++import com.jetbrains.python.edu.StudyResourceManger;
++import com.jetbrains.python.edu.StudyTaskManager;
++import com.jetbrains.python.edu.course.Task;
++import com.jetbrains.python.edu.course.TaskFile;
++import com.jetbrains.python.edu.editor.StudyEditor;
+ import java.io.File;
+ public class StudyRunAction extends DumbAwareAction {
+   public static final String ACTION_ID = "StudyRunAction";
+   public void run(Project project) {
+     Editor selectedEditor = StudyEditor.getSelectedEditor(project);
+     FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
+     assert selectedEditor != null;
+     VirtualFile openedFile = fileDocumentManager.getFile(selectedEditor.getDocument());
+     StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
+     if (openedFile != null && openedFile.getCanonicalPath() != null) {
+       String filePath = openedFile.getCanonicalPath();
+       GeneralCommandLine cmd = new GeneralCommandLine();
+       cmd.setWorkDirectory(openedFile.getParent().getCanonicalPath());
+       Sdk sdk = PythonSdkType.findPythonSdk(ModuleManager.getInstance(project).getModules()[0]);
+       if (sdk != null) {
+         String pythonPath = sdk.getHomePath();
+         if (pythonPath != null) {
+           cmd.setExePath(pythonPath);
+           TaskFile selectedTaskFile = taskManager.getTaskFile(openedFile);
+           assert selectedTaskFile != null;
+           Task currentTask = selectedTaskFile.getTask();
+           if (!currentTask.getUserTests().isEmpty()) {
+             cmd.addParameter(new File(project.getBaseDir().getPath(), StudyResourceManger.USER_TESTER).getPath());
+             cmd.addParameter(pythonPath);
+             cmd.addParameter(filePath);
+             Process p = null;
+             try {
+               p = cmd.createProcess();
+             }
+             catch (ExecutionException e) {
+               e.printStackTrace();
+             }
+             ProcessHandler handler = new OSProcessHandler(p);
+             RunContentExecutor executor = new RunContentExecutor(project, handler);
+             executor.run();
+             return;
+           }
+           try {
+             cmd.addParameter(filePath);
+             Process p = cmd.createProcess();
+             ProcessHandler handler = new OSProcessHandler(p);
+             RunContentExecutor executor = new RunContentExecutor(project, handler);
+             executor.run();
+           }
+           catch (ExecutionException e) {
+             e.printStackTrace();
+           }
+         }
+       }
+     }
+   }
+   public void actionPerformed(AnActionEvent e) {
+     run(e.getProject());
+   }
+ }
index 0000000000000000000000000000000000000000,d0e54c7c4d2dcf97192d829fad88e8e41993334f..d9ca43b3a6ea4707d6d5f3c5926a176b21d02aa8
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,84 +1,84 @@@
 -package ru.compscicenter.edide.actions;
++package com.jetbrains.python.edu.actions;
+ import com.intellij.openapi.actionSystem.AnActionEvent;
+ import com.intellij.openapi.editor.Editor;
+ import com.intellij.openapi.fileEditor.FileDocumentManager;
+ import com.intellij.openapi.fileEditor.FileEditorManager;
+ import com.intellij.openapi.project.DumbAwareAction;
+ import com.intellij.openapi.project.Project;
+ import com.intellij.openapi.ui.MessageType;
+ import com.intellij.openapi.ui.popup.Balloon;
+ import com.intellij.openapi.ui.popup.BalloonBuilder;
+ import com.intellij.openapi.ui.popup.JBPopupFactory;
+ import com.intellij.openapi.vfs.VirtualFile;
 -import ru.compscicenter.edide.StudyTaskManager;
 -import ru.compscicenter.edide.StudyUtils;
 -import ru.compscicenter.edide.course.Lesson;
 -import ru.compscicenter.edide.course.Task;
 -import ru.compscicenter.edide.course.TaskFile;
 -import ru.compscicenter.edide.editor.StudyEditor;
++import com.jetbrains.python.edu.StudyTaskManager;
++import com.jetbrains.python.edu.StudyUtils;
++import com.jetbrains.python.edu.course.Lesson;
++import com.jetbrains.python.edu.course.Task;
++import com.jetbrains.python.edu.course.TaskFile;
++import com.jetbrains.python.edu.editor.StudyEditor;
+ import javax.swing.*;
+ import java.util.Map;
+ /**
+  * author: liana
+  * data: 7/21/14.
+  */
+ abstract public class TaskNavigationAction extends DumbAwareAction {
+   public void navigateTask(Project project) {
+     Editor selectedEditor = StudyEditor.getSelectedEditor(project);
+     FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
+     assert selectedEditor != null;
+     VirtualFile openedFile = fileDocumentManager.getFile(selectedEditor.getDocument());
+     StudyTaskManager taskManager = StudyTaskManager.getInstance(project);
+     assert openedFile != null;
+     TaskFile selectedTaskFile = taskManager.getTaskFile(openedFile);
+     assert selectedTaskFile != null;
+     Task currentTask = selectedTaskFile.getTask();
+     Task nextTask = getTargetTask(currentTask);
+     if (nextTask == null) {
+       BalloonBuilder balloonBuilder =
+         JBPopupFactory.getInstance().createHtmlTextBalloonBuilder(getNavigationFinishedMessage(), MessageType.INFO, null);
+       Balloon balloon = balloonBuilder.createBalloon();
+       StudyEditor selectedStudyEditor = StudyEditor.getSelectedStudyEditor(project);
+       balloon.showInCenterOf(getButton(selectedStudyEditor));
+       return;
+     }
+     for (VirtualFile file : FileEditorManager.getInstance(project).getOpenFiles()) {
+       FileEditorManager.getInstance(project).closeFile(file);
+     }
+     int nextTaskIndex = nextTask.getIndex();
+     int lessonIndex = nextTask.getLesson().getIndex();
+     TaskFile nextFile = nextTask.getTaskFiles().values().iterator().next();
+     if (nextFile != null) {
+       VirtualFile projectDir = project.getBaseDir();
+       String lessonDirName = Lesson.LESSON_DIR + String.valueOf(lessonIndex + 1);
+       if (projectDir != null) {
+         VirtualFile lessonDir = projectDir.findChild(lessonDirName);
+         if (lessonDir != null) {
+           String taskDirName = Task.TASK_DIR + String.valueOf(nextTaskIndex + 1);
+           VirtualFile taskDir = lessonDir.findChild(taskDirName);
+           if (taskDir != null) {
+             Map.Entry<String, TaskFile> taskFile = StudyUtils.getFirst(nextTask.getTaskFiles().entrySet());
+             VirtualFile virtualFile = taskDir.findChild(taskFile.getKey());
+             if (virtualFile != null) {
+               FileEditorManager.getInstance(project).openFile(virtualFile, true);
+             }
+           }
+         }
+       }
+     }
+   }
+   protected abstract JButton getButton(StudyEditor selectedStudyEditor);
+   @Override
+   public void actionPerformed(AnActionEvent e) {
+     navigateTask(e.getProject());
+   }
+   protected abstract String getNavigationFinishedMessage();
+   protected abstract Task getTargetTask(Task sourceTask);
+ }
index 0000000000000000000000000000000000000000,45473dd22f2e6edb94a155ec361805f72883dabc..9979f6c240f50e9db96ee09a1267216a8c3a6139
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,213 +1,213 @@@
 -package ru.compscicenter.edide.actions;
++package com.jetbrains.python.edu.actions;
+ import com.intellij.icons.AllIcons;
+ import com.intellij.ide.ui.UISettings;
+ import com.intellij.openapi.actionSystem.*;
+ import com.intellij.openapi.application.ApplicationManager;
+ import com.intellij.openapi.diagnostic.Logger;
+ import com.intellij.openapi.editor.Editor;
+ import com.intellij.openapi.fileEditor.FileDocumentManager;
+ import com.intellij.openapi.project.DumbAware;
+ import com.intellij.openapi.project.DumbAwareAction;
+ import com.intellij.openapi.project.Project;
+ import com.intellij.openapi.ui.popup.JBPopup;
+ import com.intellij.openapi.ui.popup.JBPopupAdapter;
+ import com.intellij.openapi.ui.popup.JBPopupFactory;
+ import com.intellij.openapi.ui.popup.LightweightWindowEvent;
+ import com.intellij.openapi.vfs.VirtualFile;
+ import com.intellij.openapi.wm.IdeFocusManager;
+ import com.intellij.ui.tabs.TabInfo;
+ import com.intellij.ui.tabs.TabsListener;
+ import com.intellij.ui.tabs.impl.JBEditorTabs;
+ import icons.StudyIcons;
+ import org.jetbrains.annotations.NotNull;
 -import ru.compscicenter.edide.StudyTaskManager;
 -import ru.compscicenter.edide.StudyUtils;
 -import ru.compscicenter.edide.course.Task;
 -import ru.compscicenter.edide.course.TaskFile;
 -import ru.compscicenter.edide.course.UserTest;
 -import ru.compscicenter.edide.editor.StudyEditor;
 -import ru.compscicenter.edide.ui.TestContentPanel;
++import com.jetbrains.python.edu.StudyTaskManager;
++import com.jetbrains.python.edu.StudyUtils;
++import com.jetbrains.python.edu.course.Task;
++import com.jetbrains.python.edu.course.TaskFile;
++import com.jetbrains.python.edu.course.UserTest;
++import com.jetbrains.python.edu.editor.StudyEditor;
++import com.jetbrains.python.edu.ui.TestContentPanel;
+ import javax.swing.*;
+ import java.io.File;
+ import java.io.FileNotFoundException;
+ import java.io.FileOutputStream;
+ import java.io.PrintWriter;
+ import java.util.HashMap;
+ import java.util.List;
+ import java.util.Map;
+ public class WatchInputAction extends DumbAwareAction {
+   public static final String TEST_TAB_NAME = "test";
+   public static final String USER_TEST_INPUT = "input";
+   public static final String USER_TEST_OUTPUT = "output";
+   private static final Logger LOG = Logger.getInstance(WatchInputAction.class.getName());
+   private JBEditorTabs tabbedPane;
+   private Map<TabInfo, UserTest> myEditableTabs = new HashMap<TabInfo, UserTest>();
+   public void showInput(final Project project) {
+     final Editor selectedEditor = StudyEditor.getSelectedEditor(project);
+     if (selectedEditor != null) {
+       FileDocumentManager fileDocumentManager = FileDocumentManager.getInstance();
+       final VirtualFile openedFile = fileDocumentManager.getFile(selectedEditor.getDocument());
+       StudyTaskManager studyTaskManager = StudyTaskManager.getInstance(project);
+       assert openedFile != null;
+       TaskFile taskFile = studyTaskManager.getTaskFile(openedFile);
+       assert taskFile != null;
+       final Task currentTask = taskFile.getTask();
+       tabbedPane = new JBEditorTabs(project, ActionManager.getInstance(), IdeFocusManager.findInstance(), project);
+       tabbedPane.addListener(new TabsListener.Adapter() {
+         @Override
+         public void selectionChanged(TabInfo oldSelection, TabInfo newSelection) {
+           if (newSelection.getIcon() != null) {
+             int tabCount = tabbedPane.getTabCount();
+             VirtualFile taskDir = openedFile.getParent();
+             VirtualFile testsDir = taskDir.findChild(Task.USER_TESTS);
+             assert testsDir != null;
+             UserTest userTest = createUserTest(testsDir, currentTask);
+             userTest.setEditable(true);
+             TestContentPanel testContentPanel = new TestContentPanel(userTest);
+             TabInfo testTab = addTestTab(tabbedPane.getTabCount(), testContentPanel, currentTask, true);
+             myEditableTabs.put(testTab, userTest);
+             tabbedPane.addTabSilently(testTab, tabCount - 1);
+             tabbedPane.select(testTab, true);
+           }
+         }
+       });
+       List<UserTest> userTests = currentTask.getUserTests();
+       int i = 1;
+       for (UserTest userTest : userTests) {
+         String inputFileText = StudyUtils.getFileText(null, userTest.getInput(), false);
+         String outputFileText = StudyUtils.getFileText(null, userTest.getOutput(), false);
+         TestContentPanel myContentPanel = new TestContentPanel(userTest);
+         myContentPanel.addInputContent(inputFileText);
+         myContentPanel.addOutputContent(outputFileText);
+         TabInfo testTab = addTestTab(i, myContentPanel, currentTask, userTest.isEditable());
+         tabbedPane.addTabSilently(testTab, i - 1);
+         if (userTest.isEditable()) {
+           myEditableTabs.put(testTab, userTest);
+         }
+         i++;
+       }
+       TabInfo plusTab = new TabInfo(new JPanel());
+       plusTab.setIcon(StudyIcons.Add);
+       tabbedPane.addTabSilently(plusTab, tabbedPane.getTabCount());
+       final JBPopup hint =
+         JBPopupFactory.getInstance().createComponentPopupBuilder(tabbedPane.getComponent(), tabbedPane.getComponent())
+           .setResizable(true)
+           .setMovable(true)
+           .setRequestFocus(true)
+           .createPopup();
+       StudyEditor selectedStudyEditor = StudyEditor.getSelectedStudyEditor(project);
+       assert selectedStudyEditor != null;
+       hint.showInCenterOf(selectedStudyEditor.getComponent());
+       hint.addListener(new HintClosedListener(currentTask));
+     }
+   }
+   private void flushBuffer(@NotNull final StringBuilder buffer, @NotNull final File file) {
+     PrintWriter printWriter = null;
+     try {
+       printWriter = new PrintWriter(new FileOutputStream(file));
+       printWriter.print(buffer.toString());
+     }
+     catch (FileNotFoundException e) {
+       LOG.error(e);
+     }
+     finally {
+       StudyUtils.closeSilently(printWriter);
+     }
+     StudyUtils.synchronize();
+   }
+   private UserTest createUserTest(@NotNull final VirtualFile testsDir, @NotNull final Task currentTask) {
+     UserTest userTest = new UserTest();
+     List<UserTest> userTests = currentTask.getUserTests();
+     int testNum = userTests.size() + 1;
+     String inputName = USER_TEST_INPUT + testNum;
+     File inputFile = new File(testsDir.getPath(), inputName);
+     String outputName = USER_TEST_OUTPUT + testNum;
+     File outputFile = new File(testsDir.getPath(), outputName);
+     userTest.setInput(inputFile.getPath());
+     userTest.setOutput(outputFile.getPath());
+     userTests.add(userTest);
+     return userTest;
+   }
+   private TabInfo addTestTab(int nameIndex, final TestContentPanel contentPanel, @NotNull final Task currentTask, boolean toBeClosable) {
+     TabInfo testTab = toBeClosable ? createClosableTab(contentPanel, currentTask) : new TabInfo(contentPanel);
+     return testTab.setText(TEST_TAB_NAME + String.valueOf(nameIndex));
+   }
+   private TabInfo createClosableTab(TestContentPanel contentPanel, Task currentTask) {
+     TabInfo closableTab = new TabInfo(contentPanel);
+     final DefaultActionGroup tabActions = new DefaultActionGroup();
+     tabActions.add(new CloseTab(closableTab, currentTask));
+     closableTab.setTabLabelActions(tabActions, ActionPlaces.EDITOR_TAB);
+     return closableTab;
+   }
+   public void actionPerformed(AnActionEvent e) {
+     showInput(e.getProject());
+   }
+   private class HintClosedListener extends  JBPopupAdapter {
+     private final Task myTask;
+     private HintClosedListener(@NotNull final Task task) {
+       myTask = task;
+     }
+     @Override
+     public void onClosed(LightweightWindowEvent event) {
+       for (final UserTest userTest : myTask.getUserTests()) {
+         ApplicationManager.getApplication().runWriteAction(new Runnable() {
+           @Override
+           public void run() {
+             if (userTest.isEditable()) {
+               File inputFile = new File(userTest.getInput());
+               File outputFile = new File(userTest.getOutput());
+               flushBuffer(userTest.getInputBuffer(), inputFile);
+               flushBuffer(userTest.getOutputBuffer(), outputFile);
+             }
+           }
+         });
+       }
+     }
+   }
+   private class CloseTab extends AnAction implements DumbAware {
+     private final TabInfo myTabInfo;
+     private final Task myTask;
+     public CloseTab(final TabInfo info, @NotNull final Task task) {
+       myTabInfo = info;
+       myTask = task;
+     }
+     @Override
+     public void update(final AnActionEvent e) {
+       e.getPresentation().setIcon(tabbedPane.isEditorTabs() ? AllIcons.Actions.CloseNew : AllIcons.Actions.Close);
+       e.getPresentation().setHoveredIcon(tabbedPane.isEditorTabs() ? AllIcons.Actions.CloseNewHovered : AllIcons.Actions.CloseHovered);
+       e.getPresentation().setVisible(UISettings.getInstance().SHOW_CLOSE_BUTTON);
+       e.getPresentation().setText("Delete test");
+     }
+     @Override
+     public void actionPerformed(final AnActionEvent e) {
+       tabbedPane.removeTab(myTabInfo);
+       UserTest userTest = myEditableTabs.get(myTabInfo);
+       File testInputFile = new File(userTest.getInput());
+       File testOutputFile = new File(userTest.getOutput());
+       if (testInputFile.delete() && testOutputFile.delete()) {
+         StudyUtils.synchronize();
+       } else {
+         LOG.error("failed to delete user tests");
+       }
+       myTask.getUserTests().remove(userTest);
+     }
+   }
+ }
index 0000000000000000000000000000000000000000,4d1218fd12786b82167d94a91c3d7a2efd0fb2b1..89613ac7918faf894406325ea7497abe7b429466
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,104 +1,104 @@@
 -package ru.compscicenter.edide.course;
++package com.jetbrains.python.edu.course;
+ import com.intellij.openapi.application.ApplicationManager;
+ import com.intellij.openapi.diagnostic.Logger;
+ import com.intellij.openapi.util.io.FileUtil;
+ import com.intellij.openapi.vfs.VirtualFile;
+ import org.jetbrains.annotations.NotNull;
+ import java.io.File;
+ import java.io.FilenameFilter;
+ import java.io.IOException;
+ import java.util.ArrayList;
+ import java.util.List;
+ public class Course {
+   private static final Logger LOG = Logger.getInstance(Course.class.getName());
+   public static final String PLAYGROUND_DIR = "Playground";
+   public List<Lesson> lessons = new ArrayList<Lesson>();
+   public String description;
+   public String name;
+   public String myResourcePath = "";
+   public String author;
+   public static final String COURSE_DIR = "course";
+   public static final String HINTS_DIR = "hints";
+   public List<Lesson> getLessons() {
+     return lessons;
+   }
+   /**
+    * Initializes state of course
+    */
+   public void init(boolean isRestarted) {
+     for (Lesson lesson : lessons) {
+       lesson.init(this, isRestarted);
+     }
+   }
+   public String getAuthor() {
+     return author;
+   }
+   /**
+    * Creates course directory in project user created
+    *
+    * @param baseDir      project directory
+    * @param resourceRoot directory where original course is stored
+    */
+   public void create(@NotNull final VirtualFile baseDir, @NotNull final File resourceRoot) {
+     ApplicationManager.getApplication().invokeLater(
+       new Runnable() {
+         @Override
+         public void run() {
+           ApplicationManager.getApplication().runWriteAction(new Runnable() {
+             @Override
+             public void run() {
+               try {
+                 for (int i = 0; i < lessons.size(); i++) {
+                   Lesson lesson = lessons.get(i);
+                   lesson.setIndex(i);
+                   lesson.create(baseDir, resourceRoot);
+                 }
+                 baseDir.createChildDirectory(this, PLAYGROUND_DIR);
+                 File[] files = resourceRoot.listFiles(new FilenameFilter() {
+                   @Override
+                   public boolean accept(File dir, String name) {
+                    return !name.contains(Lesson.LESSON_DIR) && !name.equals("course.json") && !name.equals("hints");
+                   }
+                 });
+                 for (File file: files) {
+                   FileUtil.copy(file, new File(baseDir.getPath(), file.getName()));
+                 }
+               }
+               catch (IOException e) {
+                 LOG.error(e);
+               }
+             }
+           });
+         }
+       });
+   }
+   public void setName(String name) {
+     this.name = name;
+   }
+   public String getName() {
+     return name;
+   }
+   public void setResourcePath(@NotNull final String resourcePath) {
+     myResourcePath = resourcePath;
+   }
+   public String getResourcePath() {
+     return myResourcePath;
+   }
+   public String getDescription() {
+     return description;
+   }
+ }
index 0000000000000000000000000000000000000000,674e42bca40c7395acfd15c1441765dd5775d8a2..9f820c12c57206ba119a1557410552a26df6c7b5
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,52 +1,52 @@@
 -package ru.compscicenter.edide.course;
++package com.jetbrains.python.edu.course;
+ /**
+  * Implementation of class which contains information to be shawn in course description in tool window
+  * and when project is being created
+  */
+ public class CourseInfo {
+   private String myName;
+   private String myAuthor;
+   private String myDescription;
+   public static CourseInfo INVALID_COURSE = new CourseInfo("", "", "");
+   public CourseInfo(String name, String author, String description) {
+     myName = name;
+     myAuthor = author;
+     myDescription = description;
+   }
+   public String getName() {
+     return myName;
+   }
+   public String getAuthor() {
+     return myAuthor;
+   }
+   public String getDescription() {
+     return myDescription;
+   }
+   @Override
+   public String toString() {
+     return myName;
+   }
+   @Override
+   public boolean equals(Object o) {
+     if (this == o) return true;
+     if (o == null || getClass() != o.getClass()) return false;
+     CourseInfo that = (CourseInfo)o;
+     return that.getName().equals(myName) && that.getAuthor().equals(myAuthor)
+            && that.getDescription().equals(myDescription);
+   }
+   @Override
+   public int hashCode() {
+     int result = myName != null ? myName.hashCode() : 0;
+     result = 31 * result + (myAuthor != null ? myAuthor.hashCode() : 0);
+     result = 31 * result + (myDescription != null ? myDescription.hashCode() : 0);
+     return result;
+   }
+ }
index 0000000000000000000000000000000000000000,f59548149523163208a2ad0edd1b8babbcc64209..84396ea404d439ae3cf4186242980ac3f12c332f
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,109 +1,109 @@@
 -package ru.compscicenter.edide.course;
++package com.jetbrains.python.edu.course;
+ import com.intellij.openapi.vfs.VirtualFile;
+ import com.intellij.util.xmlb.annotations.Transient;
+ import org.jetbrains.annotations.NotNull;
+ import java.io.File;
+ import java.io.IOException;
+ import java.util.ArrayList;
+ import java.util.List;
+ public class Lesson implements Stateful{
+   public String name;
+   public List<Task> taskList = new ArrayList<Task>();
+   private Course myCourse = null;
+   public int myIndex = -1;
+   public static final String LESSON_DIR = "lesson";
+   public LessonInfo myLessonInfo = new LessonInfo();
+   public LessonInfo getLessonInfo() {
+     return myLessonInfo;
+   }
+   @Transient
+   public StudyStatus getStatus() {
+     for (Task task : taskList) {
+       StudyStatus taskStatus = task.getStatus();
+       if (taskStatus == StudyStatus.Unchecked || taskStatus == StudyStatus.Failed) {
+         return StudyStatus.Unchecked;
+       }
+     }
+     return StudyStatus.Solved;
+   }
+   @Override
+   public void setStatus(StudyStatus status) {
+     for (Task task : taskList) {
+       task.setStatus(status);
+     }
+   }
+   public List<Task> getTaskList() {
+     return taskList;
+   }
+   public String getName() {
+     return name;
+   }
+   public void setName(String name) {
+     this.name = name;
+   }
+   /**
+    * Creates lesson directory in its course folder in project user created
+    *
+    * @param courseDir    project directory of course
+    * @param resourceRoot directory where original lesson stored
 -   * @throws IOException
++   * @throws java.io.IOException
+    */
+   public void create(@NotNull final VirtualFile courseDir, @NotNull final File resourceRoot) throws IOException {
+     String lessonDirName = LESSON_DIR + Integer.toString(myIndex + 1);
+     VirtualFile lessonDir = courseDir.createChildDirectory(this, lessonDirName);
+     for (int i = 0; i < taskList.size(); i++) {
+       Task task = taskList.get(i);
+       task.setIndex(i);
+       task.create(lessonDir, new File(resourceRoot, lessonDir.getName()));
+     }
+   }
+   /**
+    * Initializes state of lesson
+    *
+    * @param course course which lesson belongs to
+    */
+   public void init(final Course course, boolean isRestarted) {
+     myCourse = course;
+     myLessonInfo.setTaskNum(taskList.size());
+     myLessonInfo.setTaskUnchecked(taskList.size());
+     for (Task task : taskList) {
+       task.init(this, isRestarted);
+     }
+   }
+   public Lesson next() {
+     List<Lesson> lessons = myCourse.getLessons();
+     if (myIndex + 1 >= lessons.size()) {
+       return null;
+     }
+     return lessons.get(myIndex + 1);
+   }
+   public void setIndex(int index) {
+     myIndex = index;
+   }
+   public int getIndex() {
+     return myIndex;
+   }
+   public Lesson prev() {
+     if (myIndex - 1 < 0) {
+       return null;
+     }
+     return myCourse.getLessons().get(myIndex - 1);
+   }
+ }
index 0000000000000000000000000000000000000000,4ff4e9452972a909e444c202443c7cd189925e17..9431632c2eddaffe67fe210266aea3b970f80313
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,43 +1,43 @@@
 -package ru.compscicenter.edide.course;
++package com.jetbrains.python.edu.course;
+ /**
+  * Implementation of class which contains information about student progress in current lesson
+  */
+ public class LessonInfo {
+   private int myTaskNum;
+   private int myTaskFailed;
+   private int myTaskSolved;
+   private int myTaskUnchecked;
+   public int getTaskNum() {
+     return myTaskNum;
+   }
+   public void setTaskNum(int taskNum) {
+     myTaskNum = taskNum;
+   }
+   public int getTaskFailed() {
+     return myTaskFailed;
+   }
+   public void setTaskFailed(int taskFailed) {
+     myTaskFailed = taskFailed;
+   }
+   public int getTaskSolved() {
+     return myTaskSolved;
+   }
+   public void setTaskSolved(int taskSolved) {
+     myTaskSolved = taskSolved;
+   }
+   public int getTaskUnchecked() {
+     return myTaskUnchecked;
+   }
+   public void setTaskUnchecked(int taskUnchecked) {
+     myTaskUnchecked = taskUnchecked;
+   }
+ }
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..10374bd94d9af8fe916040f2478ed1a40062d9df
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++package com.jetbrains.python.edu.course;
++
++public interface Stateful {
++  StudyStatus getStatus();
++  void setStatus(StudyStatus status);
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d95b42b73866c0f106ad55f568d658383d12bd7f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,8 @@@
++package com.jetbrains.python.edu.course;
++
++/**
++ * @see {@link TaskWindow#myStatus}
++ */
++public enum StudyStatus {
++  Unchecked, Solved, Failed
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a493b0ebfe8e60ce7dcb5b87af61b6848d1cfcc3
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,208 @@@
++package com.jetbrains.python.edu.course;
++
++import com.intellij.openapi.project.Project;
++import com.intellij.openapi.util.io.FileUtil;
++import com.intellij.openapi.vfs.VirtualFile;
++import com.intellij.util.xmlb.annotations.Transient;
++import org.jetbrains.annotations.NotNull;
++import org.jetbrains.annotations.Nullable;
++import com.jetbrains.python.edu.StudyUtils;
++
++import java.io.File;
++import java.io.IOException;
++import java.util.ArrayList;
++import java.util.HashMap;
++import java.util.List;
++import java.util.Map;
++
++/**
++ * Implementation of task which contains task files, tests, input file for tests
++ */
++public class Task implements Stateful{
++  public static final String TASK_DIR = "task";
++  private static final String ourTestFile = "tests.py";
++  public String name;
++  private static final String ourTextFile = "task.html";
++  public Map<String, TaskFile> taskFiles = new HashMap<String, TaskFile>();
++  private Lesson myLesson;
++  public int myIndex;
++  public List<UserTest> userTests = new ArrayList<UserTest>();
++  public static final String USER_TESTS = "userTests";
++
++  public Map<String, TaskFile> getTaskFiles() {
++    return taskFiles;
++  }
++
++  @Transient
++  public StudyStatus getStatus() {
++    for (TaskFile taskFile : taskFiles.values()) {
++      StudyStatus taskFileStatus = taskFile.getStatus();
++      if (taskFileStatus == StudyStatus.Unchecked) {
++        return StudyStatus.Unchecked;
++      }
++      if (taskFileStatus == StudyStatus.Failed) {
++        return StudyStatus.Failed;
++      }
++    }
++   &