diff --git a/homework-g596-kupriyanov/pom.xml b/homework-g596-kupriyanov/pom.xml
index 32733fc74..d862e5fed 100644
--- a/homework-g596-kupriyanov/pom.xml
+++ b/homework-g596-kupriyanov/pom.xml
@@ -11,6 +11,10 @@
homework-g596-kupriyanov
+
+ 1.4.2.RELEASE
+
+
ru.mipt.java2016
@@ -24,6 +28,49 @@
1.0.0
test
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 2.3.2
+
+
+ ru.mipt.java2016
+ homework-base
+ 1.0.0
+
+
+
+ net.sourceforge.jeval
+ jeval
+ 0.9.4
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+ ${spring.boot.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+ ${spring.boot.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+ ${spring.boot.version}
+
+
+ com.zaxxer
+ HikariCP
+ 2.5.1
+
+
+ com.h2database
+ h2
+ 1.4.193
+
+
\ No newline at end of file
diff --git a/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/BillingDao.java b/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/BillingDao.java
new file mode 100644
index 000000000..3633b0aac
--- /dev/null
+++ b/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/BillingDao.java
@@ -0,0 +1,202 @@
+package ru.mipt.java2016.homework.g596.kupriyanov.task4;
+
+/**
+ * Created by Artem Kupriyanov on 17/12/2016.
+ */
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.stereotype.Repository;
+import ru.mipt.java2016.homework.base.task1.ParsingException;
+
+import javax.annotation.PostConstruct;
+import javax.sql.DataSource;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.HashMap;
+
+@Repository
+public class BillingDao {
+ private static final Logger LOG = LoggerFactory.getLogger(BillingDao.class);
+
+ @Autowired
+ private DataSource dataSource;
+
+ private JdbcTemplate jdbcTemplate;
+
+ @PostConstruct
+ public void postConstruct() {
+ jdbcTemplate = new JdbcTemplate(dataSource, false);
+ initSchema();
+ }
+
+ public void initSchema() {
+ LOG.trace("Initializing schema");
+ jdbcTemplate.execute("CREATE SCHEMA IF NOT EXISTS billing");
+
+ // ЗДЕСЬ ДОЛЖНА БЫТЬ ХОРОШАЯ РЕАЛИЗАЦИЯ БАЗЫ ДАННЫХ
+ // Users table
+ jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS billing.users " +
+ "(username VARCHAR PRIMARY KEY, password VARCHAR, enabled BOOLEAN)");
+ jdbcTemplate.update("INSERT INTO billing.users VALUES (\'username\', \'password\', TRUE)");
+
+ // Variable table
+ jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS billing.variables " +
+ "(username VARCHAR, variable VARCHAR, val DOUBLE)");
+
+ // Functions table
+ jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS billing.functions " +
+ "(username VARCHAR, function VARCHAR, arity INTEGER, body VARCHAR)");
+ }
+
+ private Boolean checkNull(String condition) {
+ LOG.trace("check " + condition);
+ String allSelect = "SELECT * FROM " + condition;
+ return jdbcTemplate.queryForObject(
+ allSelect,
+ new Object[]{},
+ new RowMapper() {
+ @Override
+ public Boolean mapRow(ResultSet rs, int rowNum) throws SQLException {
+ Boolean flag = false;
+ while (true) {
+ if (!rs.next()) {
+ break;
+ }
+ flag = true;
+ }
+ return flag;
+ }
+ }
+ );
+ }
+
+ public BillingUser loadUser(String username) throws EmptyResultDataAccessException {
+ LOG.trace("Querying for user " + username);
+ return jdbcTemplate.queryForObject(
+ "SELECT username, password, enabled FROM billing.users WHERE username = ?",
+ new Object[]{username},
+ new RowMapper() {
+ @Override
+ public BillingUser mapRow(ResultSet rs, int rowNum) throws SQLException {
+ return new BillingUser(
+ rs.getString("username"),
+ rs.getString("password"),
+ rs.getBoolean("enabled")
+ );
+ }
+ }
+ );
+ }
+
+ public void putUser(String username, String password) {
+ try {
+ loadUser(username);
+ } catch (EmptyResultDataAccessException e) {
+ jdbcTemplate.execute("INSERT INTO billing.users VALUES (\'" + username + "\', \'" + password + "\', TRUE)");
+ }
+ }
+
+ public Double getVariable(String username, String variable) {
+ LOG.trace("Get variable " + username + " variable " + variable);
+ try {
+ return jdbcTemplate.queryForObject(
+ "select val from billing.variables " +
+ "where username = \'" + username + "\' and variable = \'" + variable + "\'",
+ new Double[]{},
+ new RowMapper() {
+ @Override
+ public Double mapRow(ResultSet rs, int rowNum) throws SQLException {
+ return new Double(
+ rs.getString("val").toString()
+ );
+ }
+ }
+ );
+ } catch (EmptyResultDataAccessException e) {
+ return 0.0;
+ }
+ }
+
+ public void putVariable(String username, String variable, Double value) {
+ LOG.trace("Put variable " + variable + " for user " + username);
+ try {
+ deleteVariable(username, variable);
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ jdbcTemplate.execute("INSERT INTO billing.variables VALUES (\'"
+ + username + "\', \'" + variable + "\', " + value.toString() + ")");
+ }
+ }
+
+ public void deleteVariable(String username, String variable) {
+ LOG.trace("Delete variable " + variable + "for user " + username);
+ jdbcTemplate.execute("DELETE FROM billing.variables WHERE username = \'"
+ + username + "\' AND variable = \'" + variable + "\'");
+ }
+
+ public HashMap getAllVariables(String username) throws ParsingException {
+ LOG.trace("List with all functions for user: " + username);
+ try {
+ return jdbcTemplate.queryForObject(
+ "SELECT username, variable, val FROM billing.variables WHERE username = ?",
+ new Object[]{username},
+ new RowMapper>() {
+ @Override
+ public HashMap mapRow(ResultSet rs, int rowNum) throws SQLException {
+ HashMap tmp = new HashMap();
+ while (true) {
+ tmp.put(rs.getString("variable"), Double.toString(rs.getDouble("val")));
+ if (!rs.next()) {
+ break;
+ }
+ }
+ return tmp;
+ }
+ }
+ );
+ } catch (EmptyResultDataAccessException e) {
+ HashMap tmp = new HashMap();
+ return tmp;
+ }
+ }
+
+ public void putFunction(String username, String function, Integer arity, String body) {
+ LOG.trace("Put function " + function + " for user " + username);
+ try {
+ deleteFunction(username, function);
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ jdbcTemplate.execute("INSERT INTO billing.functions VALUES (\'"
+ + username + "\', \'" + function + "\', " + arity.toString() + ", \'"
+ + body + "\')");
+ }
+ }
+
+ public String getFunction(String username, String function) {
+ LOG.trace("Load function " + function + " for user " + username);
+ return jdbcTemplate.queryForObject(
+ "SELECT body FROM billing.functions WHERE username = \'"
+ + username + "\' AND function = \'" + function + "\'",
+ new String[]{},
+ new RowMapper() {
+ @Override
+ public String mapRow(ResultSet rs, int rowNum) throws SQLException {
+ return rs.getString("body");
+ }
+ }
+ );
+ }
+
+ public void deleteFunction(String username, String function) {
+ LOG.info("Delete function " + function + " for user " + username);
+ jdbcTemplate.execute("DELETE FROM billing.functions WHERE username = \'" +
+ username + "\' AND function = \'" + function + "\'");
+ }
+}
\ No newline at end of file
diff --git a/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/BillingDatabaseConfiguration.java b/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/BillingDatabaseConfiguration.java
new file mode 100644
index 000000000..f39ab15d1
--- /dev/null
+++ b/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/BillingDatabaseConfiguration.java
@@ -0,0 +1,30 @@
+package ru.mipt.java2016.homework.g596.kupriyanov.task4;
+
+/**
+ * Created by Artem Kupriyanov on 17/12/2016.
+ */
+
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.sql.DataSource;
+
+@Configuration
+public class BillingDatabaseConfiguration {
+ @Bean
+ public DataSource billingDataSource(
+ @Value("${ru.mipt.java2016.homework.g000.lavrentyev.task4.jdbcUrl}") String jdbcUrl,
+ @Value("${ru.mipt.java2016.homework.g000.lavrentyev.task4.username:}") String username,
+ @Value("${ru.mipt.java2016.homework.g000.lavrentyev.task4.password:}") String password
+ ) {
+ HikariConfig config = new HikariConfig();
+ config.setDriverClassName(org.h2.Driver.class.getName());
+ config.setJdbcUrl(jdbcUrl);
+ config.setUsername(username);
+ config.setPassword(password);
+ return new HikariDataSource(config);
+ }
+}
diff --git a/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/BillingUser.java b/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/BillingUser.java
new file mode 100644
index 000000000..75e2e37fd
--- /dev/null
+++ b/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/BillingUser.java
@@ -0,0 +1,73 @@
+package ru.mipt.java2016.homework.g596.kupriyanov.task4;
+
+/**
+ * Created by Artem Kupriyanov on 17/12/2016.
+ */
+
+public class BillingUser {
+ private final String username;
+ private final String password;
+ private final boolean enabled;
+
+ public BillingUser(String username, String password, boolean enabled) {
+ if (username == null) {
+ throw new IllegalArgumentException("Null username is not allowed");
+ }
+ if (password == null) {
+ throw new IllegalArgumentException("Null password is not allowed");
+ }
+ this.username = username;
+ this.password = password;
+ this.enabled = enabled;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ @Override
+ public String toString() {
+ return "BillingUser{" +
+ "username='" + username + '\'' +
+ ", password='" + password + '\'' +
+ ", enabled=" + enabled +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ BillingUser that = (BillingUser) o;
+
+ if (enabled != that.enabled) {
+ return false;
+ }
+ if (!username.equals(that.username)) {
+ return false;
+ }
+ return password.equals(that.password);
+
+ }
+
+ @Override
+ public int hashCode() {
+ int result = username.hashCode();
+ result = 31 * result + password.hashCode();
+ result = 31 * result + (enabled ? 1 : 0);
+ return result;
+ }
+}
diff --git a/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/CalculatorController.java b/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/CalculatorController.java
new file mode 100644
index 000000000..52754b0c9
--- /dev/null
+++ b/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/CalculatorController.java
@@ -0,0 +1,118 @@
+package ru.mipt.java2016.homework.g596.kupriyanov.task4;
+
+/**
+ * Created by Artem Kupriyanov on 17/12/2016.
+ */
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.Authentication;
+import org.springframework.web.bind.annotation.*;
+import ru.mipt.java2016.homework.base.task1.Calculator;
+import ru.mipt.java2016.homework.base.task1.ParsingException;
+
+@RestController
+public class CalculatorController {
+ private static final Logger LOG = LoggerFactory.getLogger(CalculatorController.class);
+ @Autowired
+ private Calculator calculator;
+ @Autowired
+ private BillingDao billingDao;
+
+ @RequestMapping(path = "/ping", method = RequestMethod.GET, produces = "text/plain")
+ public String echo() {
+ return "OK\n";
+ }
+
+ @RequestMapping(path = "/", method = RequestMethod.GET, produces = "text/html")
+ public String main(@RequestParam(required = false) String name) {
+ if (name == null) {
+ name = "world";
+ }
+ return "" +
+ "FediqApp" +
+ "Hello, " + name + "!
" +
+ "";
+ }
+
+ @RequestMapping(path = "/eval", method = RequestMethod.POST, consumes = "text/plain", produces = "text/plain")
+ public String eval(Authentication auth, @RequestBody String expression) throws ParsingException {
+ LOG.debug("Evaluation request: [" + expression + "]");
+ String username = auth.getName();
+ double result = calculator.calculate(expression);
+ //String result = functionalCalculate(expression, username);
+ LOG.trace("Result: " + result);
+ //return result;
+ return Double.toString(result) + "\n";
+ }
+
+ @RequestMapping(path = "/reg/{userName}", method = RequestMethod.PUT,
+ consumes = "text/plain", produces = "text/plain")
+ public void reg(@PathVariable String userName, @RequestBody String passwd) throws ParsingException {
+ LOG.debug("New user: [" + userName + ' ' + passwd + "]");
+ billingDao.putUser(userName, passwd);
+ }
+
+ private String functionalCalculate(String expression, String username) throws ParsingException {
+ String goodExpression = expression;
+ Parser parser = new Parser(expression, username);
+ for (String function : parser.getFunction()) {
+ if (expression.indexOf(function) != -1) {
+ String subExpression = parser.expressionInFunction(expression, function);
+ String functionAndOperand = function + subExpression;
+ expression.replace(functionAndOperand, functionalCalculate(subExpression, username));
+ }
+ }
+ goodExpression = parser.work();
+ double result = calculator.calculate(goodExpression);
+ return Double.toString(result) + "\n";
+ }
+
+ @RequestMapping(path = "/variable/{variableName}", method = RequestMethod.PUT,
+ consumes = "text/plain", produces = "text/plain")
+ public void putVariable(Authentication auth,
+ @PathVariable String variableName, @RequestParam(value = "value") Double value) {
+ String username = auth.getName();
+ billingDao.putVariable(username, variableName, value);
+ }
+
+ @RequestMapping(path = "/variable/{variableName}", method = RequestMethod.GET,
+ consumes = "text/plain", produces = "text/plain")
+ public String getVariable(Authentication auth, @PathVariable String variableName) {
+ String username = auth.getName();
+ Double value = billingDao.getVariable(username, variableName);
+ return value.toString() + "\n";
+ }
+
+ @RequestMapping(path = "/variable/{variableName}", method = RequestMethod.DELETE,
+ consumes = "text/plain", produces = "text/plain")
+ public void deleteVariable(Authentication authentication, @PathVariable String variableName) {
+ String username = authentication.getName();
+ billingDao.deleteVariable(username, variableName);
+ }
+
+ @RequestMapping(path = "/function/{functionName}", method = RequestMethod.PUT,
+ consumes = "text/plain", produces = "text/plain")
+ public void putFunction(Authentication authentication, @PathVariable String functionName,
+ @RequestParam(value = "arity") Integer arity, @RequestBody String body) {
+ String username = authentication.getName();
+ LOG.trace(username);
+ billingDao.putFunction(username, functionName, arity, body);
+ }
+
+ @RequestMapping(path = "/function/{functionName}", method = RequestMethod.DELETE,
+ consumes = "text/plain", produces = "text/plain")
+ public void deleteFunction(Authentication authentication, @PathVariable String functionName) {
+ String username = authentication.getName();
+ billingDao.deleteFunction(username, functionName);
+ }
+
+ @RequestMapping(path = "/function/{functionName}", method = RequestMethod.GET,
+ consumes = "text/plain", produces = "text/plain")
+ public String getFunction(Authentication authentication, @PathVariable String functionName) {
+ String username = authentication.getName();
+ String res = billingDao.getFunction(username, functionName);
+ return res + "\n";
+ }
+}
\ No newline at end of file
diff --git a/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/FediqApplication.java b/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/FediqApplication.java
new file mode 100644
index 000000000..241551283
--- /dev/null
+++ b/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/FediqApplication.java
@@ -0,0 +1,48 @@
+package ru.mipt.java2016.homework.g596.kupriyanov.task4;
+
+/**
+ * Created by Artem Kupriyanov on 17/12/2016.
+ */
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.Banner;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import ru.mipt.java2016.homework.base.task1.Calculator;
+import ru.mipt.java2016.homework.g596.kupriyanov.task1.MyCalculator;
+
+
+//запуск
+// curl http://localhost:9001/eval \
+// -X POST \
+// -H "Content-Type: text/plain" \
+// -H "Authorization: Basic $(echo -n "username:password" | base64)" \
+// --data-raw "44*3+2"
+
+
+@EnableAutoConfiguration
+@Configuration
+@ComponentScan(basePackageClasses = FediqApplication.class)
+public class FediqApplication {
+
+ @Bean
+ public Calculator calculator() {
+ return new MyCalculator();
+ }
+
+ @Bean
+ public EmbeddedServletContainerCustomizer customizer(
+ @Value("${ru.mipt.java2016.homework.g000.lavrentyev.task4.httpPort:9001}") int port) {
+ return container -> container.setPort(port);
+ }
+
+ public static void main(String[] args) {
+ SpringApplication application = new SpringApplication(FediqApplication.class);
+ application.setBannerMode(Banner.Mode.OFF);
+ application.run(args);
+ }
+}
diff --git a/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/Parser.java b/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/Parser.java
new file mode 100644
index 000000000..0992809c3
--- /dev/null
+++ b/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/Parser.java
@@ -0,0 +1,77 @@
+package ru.mipt.java2016.homework.g596.kupriyanov.task4;
+
+import ru.mipt.java2016.homework.base.task1.ParsingException;
+
+import java.util.*;
+
+/**
+ * Created by Artem Kupriyanov on 19/12/2016.
+ */
+
+
+public class Parser extends BillingDao {
+ private String expression;
+ private String username;
+ private Map variables;
+ private List functions;
+
+ Parser(String exp, String usern) {
+ expression = exp;
+ username = usern;
+ try {
+ variables = getAllVariables(username);
+ } catch (ParsingException e) {
+ variables = new HashMap<>();
+ }
+ //functions =
+ }
+
+ class LengthComparator implements Comparator {
+ @Override
+ public int compare(String s1, String s2) {
+ return -(s1.length() - s2.length()); // по убыванию
+ }
+ }
+
+ private void substituteVariable() {
+ LengthComparator myComparator = new LengthComparator();
+ List sortedVariables = new ArrayList<>(variables.keySet());
+ Collections.sort(sortedVariables, myComparator);
+ for (String variable: sortedVariables) {
+ if (expression.contains(variable)) {
+ expression.replaceAll(variable, variables.get(variable));
+ }
+ }
+ }
+
+ public String expressionInFunction(String express, String function) {
+ int start = express.indexOf(function) + function.length();
+ int bracketBalance = 0;
+ if (express.charAt(start) != '(') {
+ return null;
+ }
+ int end = start;
+ while (end != express.length()) {
+ if (express.charAt(end) == '(') {
+ bracketBalance++;
+ }
+ if (express.charAt(end) == ')') {
+ bracketBalance--;
+ }
+ if (bracketBalance == 0) {
+ break;
+ }
+ end++;
+ }
+ return express.substring(start, end);
+ }
+
+ public String work() {
+ substituteVariable();
+ return expression;
+ }
+
+ public List getFunction() {
+ return functions;
+ }
+}
diff --git a/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/SecurityServiceConfiguration.java b/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/SecurityServiceConfiguration.java
new file mode 100644
index 000000000..2e016fd5f
--- /dev/null
+++ b/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/SecurityServiceConfiguration.java
@@ -0,0 +1,59 @@
+package ru.mipt.java2016.homework.g596.kupriyanov.task4;
+
+/**
+ * Created by Artem Kupriyanov on 17/12/2016.
+ */
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+
+import java.util.Collections;
+
+@Configuration
+@EnableWebSecurity
+public class SecurityServiceConfiguration extends WebSecurityConfigurerAdapter {
+ private static final Logger LOG = LoggerFactory.getLogger(SecurityServiceConfiguration.class);
+
+ @Autowired
+ private BillingDao billingDao;
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ LOG.info("Configuring security");
+ http
+ .httpBasic().realmName("Calculator").and()
+ .formLogin().disable()
+ .logout().disable()
+ .csrf().disable()
+ .authorizeRequests()
+ .antMatchers("/eval/**").authenticated()
+ .anyRequest().permitAll();
+ }
+
+ @Autowired
+ public void registerGlobalAuthentication(AuthenticationManagerBuilder auth) throws Exception {
+ LOG.info("Registering global user details service");
+ auth.userDetailsService(username -> {
+ try {
+ BillingUser user = billingDao.loadUser(username);
+ return new User(
+ user.getUsername(),
+ user.getPassword(),
+ Collections.singletonList(() -> "AUTH")
+ );
+ } catch (EmptyResultDataAccessException e) {
+ LOG.warn("No such user: " + username);
+ throw new UsernameNotFoundException(username);
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/start.txt b/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/start.txt
new file mode 100644
index 000000000..35fe69bb0
--- /dev/null
+++ b/homework-g596-kupriyanov/src/main/java/ru/mipt/java2016/homework/g596/kupriyanov/task4/start.txt
@@ -0,0 +1,28 @@
+запуск
+ curl http://localhost:9001/eval \
+ -X POST \
+ -H "Content-Type: text/plain" \
+ -H "Authorization: Basic $(echo -n "username:password" | base64)" \
+ --data-raw "44*3+2"
+
+авторизация
+curl http://localhost:9001/reg?args="artemkaa, 599" -X POST -H "Content-Type: text/plain" -H \
+"Authorization: Basic $(echo -n "username:password" | base64)"
+
+положить переменную
+curl http://localhost:9001/variable/pi?value="3.1415926" -X PUT -H "Content-Type: text/plain" -H \
+"Authorization: Basic $(echo -n "username:password" | base64)"
+
+curl http://localhost:9001/variable/pi -X GET -H "Content-Type: text/plain" -H \
+"Authorization: Basic $(echo -n "username:password" | base64)"
+
+ curl http://localhost:9001/reg/artemkaa \
+ -X PUT \
+ -H "Content-Type: text/plain" \
+ --data-raw "599"
+
+curl http://localhost:9001/function/sum?arity="2" -X PUT -H "Content-Type: text/plain" -H \
+"Authorization: Basic $(echo -n "username:password" | base64)" --data "x+y"
+
+curl http://localhost:9001/function/sum -X GET -H "Content-Type: text/plain" -H \
+"Authorization: Basic $(echo -n "username:password" | base64)"
\ No newline at end of file