diff --git a/.gitignore b/.gitignore index 4d29575..c4db695 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,15 @@ npm-debug.log* yarn-debug.log* yarn-error.log* + +# database contents +/dl-limit-items.csv +/public/database +/public/credits +/public/documents +/public/hackathon +/public/mediawiki +/src/database/assets/*.json +/src/credits/assets/*.json +/src/pico/assets/*.json +/src/mediawiki/assets/*.json diff --git a/etc/common.inc.php b/etc/common.inc.php new file mode 100644 index 0000000..ce60f39 --- /dev/null +++ b/etc/common.inc.php @@ -0,0 +1,197 @@ + $v) { + if (is_string($v)) { + $v = $textutil->html_numeric_entities($v); + $v = mb_decode_numericentity($v, array(0x0, 0x10000, 0, 0xfffff), 'UTF-8'); + $data[$k] = \Normalizer::normalize(trim($v), \Normalizer::FORM_C); + } elseif (null === $v) { + $data[$k] = ''; + } + } + } + + public static function convertToInt(&$data, $keys, $zerofill = false) + { + foreach ($keys as $key) { + if (isset($data[$key])) { + $data[$key] = '' === $data[$key] ? ($zerofill ? 0 : null) : (int) $data[$key]; + } + } + } + + public static function dropColumn(&$data, $keys) + { + foreach ($keys as $key) { + if (isset($data[$key])) { + unset($data[$key]); + } + } + } + + public static function fileCopy($from, $to) + { + system('rsync -aq '.escapeshellarg($from).' '.escapeshellarg($to), $ret); + + return 0 === $ret; + } + + public static function fixHtml($text) + { + static $config = [ + //'clean' => true, + 'hide-comments' => true, + 'indent' => true, + 'output-xhtml' => true, + 'preserve-entities' => true, + 'show-body-only' => true, + 'wrap' => 0, + 'input-encoding' => 'utf8', + 'output-encoding' => 'utf8', + 'output-bom' => false, + ]; + $text = tidy_repair_string($text, $config); + $text = preg_replace('/]*)>((?:\s*]*>.*<\/caption>)?\s*)]*)>/Us', '\2', $text); + $text = preg_replace('/<\/tr>(\s*)<\/table>/s', '\1', $text); + + return $text; + } + + public static function tableExists($name) + { + global $xoopsDB; + $prefix = $xoopsDB->prefix(); + $sql = <<< SQL +SELECT 1 + FROM `${prefix}_${name}` + LIMIT 1 +SQL; + if (!($res = $xoopsDB->query($sql))) { + return false; + } + $xoopsDB->freeRecordSet($res); + + return true; + } + + public static function makeDirectory($dirname) + { + $path = MYDUMPTOOL_OUTPUTDIR.('' !== $dirname ? '/'.$dirname : ''); + if (!is_dir($path)) { + if (!@mkdir($path)) { + exit('Failed to create directory: '.$path.PHP_EOL); + } + } + } + + public static function saveJson($fname, $data) + { + $path = MYDUMPTOOL_OUTPUTDIR.'/'.$fname; + if (false === file_put_contents($path, json_encode($data, JSON_UNESCAPED_UNICODE))) { + exit('Failed to save json file: '.$path.PHP_EOL); + } + } + + public static function fileDownload($url, $fpath) + { + $fp = fopen($fpath, 'w'); + if (false === $fp) { + exit('Failed to open file: '.$fpath.PHP_EOL); + } + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($curl, CURLOPT_AUTOREFERER, true); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_FAILONERROR, true); + curl_setopt($curl, CURLOPT_FILE, $fp); + curl_setopt($curl, CURLOPT_TIMEOUT, 10); + $ret = curl_exec($curl); + fclose($fp); + if (false === $ret) { + exit('Failed to download file, unexpected error: '.$url.PHP_EOL); + } + $code = curl_getinfo($curl, CURLINFO_HTTP_CODE); + if (200 !== $code) { + exit('Failed to download file, invalid status code('.$code.'): '.$url.PHP_EOL); + } + curl_close($curl); + + return true; + } + + public static function getMimeType($fpath) + { + $finfo = finfo_open(FILEINFO_MIME); + $mime = finfo_file($finfo, $fpath); + finfo_close($finfo); + $mime = preg_replace('/(;.*)$/', '', $mime); + + return $mime; + } +} diff --git a/etc/config.inc.php b/etc/config.inc.php new file mode 100644 index 0000000..ac6a14d --- /dev/null +++ b/etc/config.inc.php @@ -0,0 +1,9 @@ +prefix(); + +$table = 'nipfcredits_organization'; +if (!MyDumpTool::tableExists($table)) { + exit('credits module not found'.PHP_EOL); +} +MyDumpTool::makeDirectory('src/credits'); +MyDumpTool::makeDirectory('src/credits/assets'); + +// organization +$organization = []; +$sql = <<< SQL +SELECT + `o`.* + FROM `${prefix}_nipfcredits_organization` AS `o` +SQL; +if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); +} +while ($row = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($row); + $organization = $row; +} +$xoopsDB->freeRecordSet($res); +$organization['com_email'] = str_replace('@', ' (at) ', $organization['com_email']); +$organization['com_url'] = XOOPS_URL; +$organization['institute'] = 'Neuroinformatics Unit, RIKEN Center for Brain Science'; +$organization['url'] = 'https://www.ni.riken.jp/'; +$organization['email'] = 'office (at) ni.riken.jp'; +$organization['address'] = 'Hirosawa 2-1, Wako, Saitama, 351-0198 Japan'; +$organization['tel'] = '+81 48 (462) 1111'; + +// member +$member = []; +$sql = <<< SQL +SELECT + `m`.* + FROM `${prefix}_nipfcredits_member` AS `m` + ORDER BY `m`.`weight` +SQL; +if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); +} +while ($row = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($row); + $member[] = $row; +} +$xoopsDB->freeRecordSet($res); +$opage = getOrganizationPage($organization, $member); +//var_dump($opage); + +// pages +$pages = []; +$sql = <<< SQL +SELECT + `p`.* + FROM `${prefix}_nipfcredits_page` AS `p` + ORDER BY `p`.`weight` +SQL; +if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); +} +while ($row = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($row); + myDumpTool::convertToInt($row, ['pid', 'weight', 'lastupdate']); + $content = replaceOrganization($row['content'], $organization); + $content = MyDumpTool::fixHtml($content); + $content = preg_replace('/href="(?:\.\/|'.preg_quote(XOOPS_URL, '/').'\/modules\/credits\/)?index\.php\?id=(\d+)"/', 'href="/credits/\1"', $content); + $imageUrl = []; + $content = preg_replace_callback('/]*)src="([^"]+)"([^>]*)\/>/Usi', function ($matches) use (&$imageUrl, $row) { + $url = $matches[2]; + if (preg_match('/^(.+)\/([^\/]+\.(:?png|jpg|gif|svg))(\?.+)?$/i', $url, $m)) { + if (!isset($imageUrl[$m[1]])) { + $imageUrl[$m[1]] = count($imageUrl) + 1; + } + $id = $imageUrl[$m[1]]; + $fname = '/credits/images/'.$row['pid'].'/'.$id.'/'.urldecode($m[2]); + $fpath = MYDUMPTOOL_OUTPUTDIR.'/public'.$fname; + if (!file_exists($fpath)) { + MyDumpTool::makeDirectory('public/credits'); + MyDumpTool::makeDirectory('public/credits/images'); + MyDumpTool::makeDirectory('public/credits/images/'.$row['pid']); + MyDumpTool::makeDirectory('public/credits/images/'.$row['pid'].'/'.$id); + if (preg_match('/^\//', $url)) { + $url = XOOPS_URL.$url; + } + MyDumpTool::fileDownload($url, $fpath); + } + $url = '/credits/images/'.$row['pid'].'/'.$id.'/'.$m[2]; + } + + return ''; + }, $content); + $content = preg_replace('/]*)href="(?:'.preg_quote(XOOPS_URL, '/').')?\/modules\/xoonips\/(?:register|edit|user)[^"]*"(?:[^>]*)>(.*)<\/a>/Usi', '\1(closed)', $content); + $row['content'] = $content; + MyDumpTool::dropColumn($row, ['weight']); + $pages[] = $row; +} +$xoopsDB->freeRecordSet($res); +//var_dump($pages); + +$data = [ + 'organization' => $opage, + 'pages' => $pages, +]; +MyDumpTool::saveJson('src/credits/assets/credits.json', $data); + +function replaceOrganization($text, $org) +{ + $textutil = xoonips_getutility('text'); + $map = [ + '{COMMITTEE_NAME}' => $textutil->html_special_chars($org['committee']), + '{COMMITTEE_EMAIL}' => ''.$textutil->html_special_chars($org['com_email']).'(committee email has been closed)', + '{INSTITUTE_NAME}' => $textutil->html_special_chars($org['institute']), + '{INSTITUTE_URL}' => $textutil->html_special_chars($org['url']), + '{INSTITUTE_EMAIL}' => $textutil->html_special_chars($org['email']), + '{INSTITUTE_ADDRESS}' => $textutil->html_special_chars($org['address']), + '{INSTITUTE_TEL}' => $textutil->html_special_chars($org['tel']), + '{PLATFORM_URL}' => XOOPS_URL, + ]; + + return str_replace(array_keys($map), $map, $text); +} + +function getOrganizationPage($org, $member) +{ + $textutil = xoonips_getutility('text'); + $members = []; + foreach ($member as $m) { + $members[] = '
  • '.$textutil->html_special_chars($m['name'].' : '.$m['division']).'
  • '; + } + $members = implode("\n", $members); + $committee = $textutil->html_special_chars($org['committee']); + $institute = $textutil->html_special_chars($org['institute']); + $address = $textutil->html_special_chars($org['address']); + $url = $textutil->html_special_chars($org['url']); + $html = <<< HTML +

    ${committee}

    +
      +
    • Members +
        +${members} +
      +
    • +
    +HTML; + + return $html; +} diff --git a/etc/dumpMediaWiki.php b/etc/dumpMediaWiki.php new file mode 100644 index 0000000..ebb76e6 --- /dev/null +++ b/etc/dumpMediaWiki.php @@ -0,0 +1,198 @@ +makedir(__DIR__.'/data'); + $this->makedir(__DIR__.'/data/src'); + $this->makedir(__DIR__.'/data/src/mediawiki'); + $this->makedir(__DIR__.'/data/src/mediawiki/assets'); + $this->makedir(__DIR__.'/data/public'); + $this->makedir(__DIR__.'/data/public/mediawiki'); + $this->makedir(__DIR__.'/data/public/mediawiki/images'); + $this->makedir(__DIR__.'/data/public/mediawiki/contents'); + $this->makedir(__DIR__.'/temp'); + $this->makedir(__DIR__.'/temp/mediawiki'); + $url = API_URL.'?action=query&list=allpages&aplimit=500&utf8=&format=json'; + $json = $this->fetchData($url); + $data = json_decode($json, true); + $allpages = $data['query']['allpages']; + $num = 0; + $start = 0; + foreach ($allpages as $page) { + if ($num < $start) { + ++$num; + continue; + } + $name = urlencode(str_replace(' ', '_', $page['title'])); + $url = API_URL.'?action=parse&format=json&page='.$name; + $json = $this->fetchData($url); + $data = json_decode($json, true); + $detail = $data['parse']; + echo $num.'('.$detail['revid'].'): '.$page['title'].PHP_EOL; + $mwlist[] = [ + 'id' => (int) $detail['revid'], + 'title' => $page['title'], + ]; + if (!isset($detail['images'])) { + var_dump($json); + var_dump($page); + var_dump($name); + var_dump($data); + exit(); + } + foreach ($detail['images'] as $image) { + $fpath = $this->getImagePath(IMAGE_DIR, $image); + if (!file_exists($fpath)) { + exit('File not found: '.$fpath.PHP_EOL); + } + $dfpath = $this->getImagePath(DEST_IMAGE_DIR, $image); + $pddpath = dirname($dfpath); + $ppddpath = dirname($pddpath); + $this->makedir($ppddpath); + $this->makedir($pddpath); + $this->fileCopy($fpath, $dfpath); + } + $text = $this->fixHtml($detail['text']['*']); + $title = $detail['title']; + $sections = []; + foreach ($detail['sections'] as $section) { + $sections[] = [ + 'toclevel' => $section['toclevel'], + 'line' => $section['line'], + 'number' => $section['number'], + 'anchor' => $section['anchor'], + ]; + } + $data = [ + 'title' => $title, + 'text' => $text, + 'sections' => $sections, + ]; + $fname = __DIR__.'/temp/mediawiki/'.$detail['revid'].'.dump.json'; + file_put_contents($fname, json_encode($data, JSON_UNESCAPED_UNICODE)); + ++$num; + } + $fname = __DIR__.'/data/src/mediawiki/assets/contents.json'; + file_put_contents($fname, json_encode($mwlist, JSON_UNESCAPED_UNICODE)); + + echo "Hello, World!\n"; + } + + public function fixHtml($text) + { + $text = preg_replace('/\[<\/span>
    edit<\/a>\]<\/span><\/span>/Us', '', $text); + $text = preg_replace('/([^<]+)<\/a>/Us', '\1', $text); + $text = preg_replace('/
  • \s*(.*)\s*<\/li>/Us', '
  • \1
  • ', $text); + $text = preg_replace('//Us', '', $text); + $text = trim($text); + + return $text; + } + + public function makedir($path) + { + if (is_dir($path)) { + return true; + } + if (false === @mkdir($path)) { + exit('Failed to create directroy: '.$path.PHP_EOL); + } + + return true; + } + + public function getImagePath($basedir, $fname) + { + $hash = md5($fname); + + return $basedir.'/'.substr($hash, 0, 1).'/'.substr($hash, 0, 2).'/'.$fname; + } + + public function fileCopy($from, $to) + { + system('rsync -aq '.escapeshellarg($from).' '.escapeshellarg($to), $ret); + if (0 !== $ret) { + exit('Failed to copy file: '.$from.' -> '.$to.PHP_EOL); + } + + return 0 === $ret; + } + + public function fetchData($url) + { + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($curl, CURLOPT_AUTOREFERER, true); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_FAILONERROR, true); + curl_setopt($curl, CURLOPT_TIMEOUT, 5); + $ret = curl_exec($curl); + if (false === $ret) { + exit('Failed to fetch data, unexpected error: '.$url.PHP_EOL); + } + $code = curl_getinfo($curl, CURLINFO_HTTP_CODE); + if (200 !== $code) { + exit('Failed to fetch data, invalid status code('.$code.'): '.$url.PHP_EOL); + } + curl_close($curl); + + return $ret; + } + + public function fileDownload($url, $fpath) + { + $fp = fopen($fpath, 'w'); + if (false === $fp) { + exit('Failed to open file: '.$fpath.PHP_EOL); + } + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($curl, CURLOPT_AUTOREFERER, true); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($curl, CURLOPT_FAILONERROR, true); + curl_setopt($curl, CURLOPT_FILE, $fp); + curl_setopt($curl, CURLOPT_TIMEOUT, 5); + $ret = curl_exec($curl); + fclose($fp); + if (false === $ret) { + exit('Failed to download file, unexpected error: '.$url.PHP_EOL); + } + $code = curl_getinfo($curl, CURLINFO_HTTP_CODE); + if (200 !== $code) { + exit('Failed to download file, invalid status code('.$code.'): '.$url.PHP_EOL); + } + curl_close($curl); + + return true; + } +} + +$maintClass = DumpMediaWiki::class; + +require_once RUN_MAINTENANCE_IF_MAIN; diff --git a/etc/dumpPico.php b/etc/dumpPico.php new file mode 100644 index 0000000..a76348f --- /dev/null +++ b/etc/dumpPico.php @@ -0,0 +1,163 @@ +prefix(); + $table = $pico.'_contents'; + if (!MyDumpTool::tableExists($table)) { + exit('pico('.$pico.') module not found'.PHP_EOL); + } + MyDumpTool::makeDirectory('public/'.$pico); + MyDumpTool::makeDirectory('public/'.$pico.'/images'); + $moduleHandler = xoops_gethandler('module'); + $module = $moduleHandler->getByDirname($pico); + $moduleConfigHandler = xoops_gethandler('config'); + $moduleConfig = $moduleConfigHandler->getConfigsByDirname($pico); + $permObj = PicoPermission::getInstance(); + $perms = $permObj->getPermissions($pico); + $categoryHandler = new PicoCategoryHandler($pico, $perms); + $contentHandler = new PicoContentHandler($pico); + $cats = $categoryHandler->getAllCategories(); + $confContents = []; + $confCategories = []; + foreach ($cats as $cat) { + $catData = $cat->getData(); + $modConfig = $cat->getOverriddenModConfig(); + $link = pico_common_make_category_link4html($modConfig, $catData, $pico); + MyDumpTool::decode($catData); + $confCategories[] = [ + 'id' => $catData['id'], + 'title' => $catData['cat_title'], + 'desc' => (string) $catData['cat_desc'], + 'pid' => (int) $catData['pid'], + 'weight' => (int) $catData['cat_weight'], + 'link' => $link, + ]; + $contents = $contentHandler->getCategoryContents($cat); + foreach ($contents as $content) { + $data = $content->getData(); + $link = pico_common_make_content_link4html($modConfig, $data); + MyDumpTool::decode($data); + $content = MyDumpTool::fixHtml($data['body_cached']); + $imageId = 1; + $dataId = []; + $content = preg_replace_callback('/]*)src="(.*)"([^>]*)\/>/Us', function ($matches) use (&$imageId, $pico, $data, $link) { + $url = $matches[2]; + if (!preg_match('/^http/', $url)) { + if (preg_match('/^\//', $url)) { + $url = XOOPS_URL.$url; + } else { + $xpath = dirname($link); + $url = XOOPS_URL.'/modules/'.$pico.'/'.$xpath.'/'.$url; + } + } + $fname = '/'.$pico.'/images/'.$data['id'].'_'.$imageId.'.dat'; + $fpath = MYDUMPTOOL_OUTPUTDIR.'/public'.$fname; + MyDumpTool::fileDownload($url, $fpath); + $mime = MyDumpTool::getMimeType($fpath); + switch ($mime) { + case 'image/gif': + $fpath_ = preg_replace('/.dat$/', '.gif', $fpath); + $fname = preg_replace('/.dat$/', '.gif', $fname); + rename($fpath, $fpath_); + $fpath = $fpath_; + break; + case 'image/png': + $fpath_ = preg_replace('/.dat$/', '.png', $fpath); + $fname = preg_replace('/.dat$/', '.png', $fname); + rename($fpath, $fpath_); + $fpath = $fpath_; + break; + case 'image/jpeg': + $fpath_ = preg_replace('/.dat$/', '.jpeg', $fpath); + $fname = preg_replace('/.dat$/', '.jpeg', $fname); + rename($fpath, $fpath_); + $fpath = $fpath_; + break; + default: + exit('unknown mime type '.$mime.' found: '.$fname.' from '.$url.PHP_EOL); + } + ++$imageId; + + return ''; + }, $content); + $content = preg_replace_callback('/
    ]*)href="([^"]+)"([^>]*)>/Us', function ($matches) use (&$dataId, $pico, $data, $link) { + $url = $matches[2]; + if (preg_match('/^(.+)\/([^\/]+\.pdf)(\?.+)?$/', $url, $m)) { + if (!isset($dataId[$m[1]])) { + $dataId[$m[1]] = count($dataId) + 1; + } + $id = $dataId[$m[1]]; + $fname = '/'.$pico.'/data/'.$data['id'].'/'.$id.'/'.urldecode($m[2]); + $fpath = MYDUMPTOOL_OUTPUTDIR.'/public'.$fname; + if (!file_exists($fpath)) { + MyDumpTool::makeDirectory('public/'.$pico.'/data'); + MyDumpTool::makeDirectory('public/'.$pico.'/data/'.$data['id']); + MyDumpTool::makeDirectory('public/'.$pico.'/data/'.$data['id'].'/'.$id); + if (preg_match('/^\//', $url)) { + $url = XOOPS_URL.$url; + } + MyDumpTool::fileDownload($url, $fpath); + } + $url = '/'.$pico.'/data/'.$data['id'].'/'.$id.'/'.$m[2]; + } + + return ''; + }, $content); + $item = [ + 'id' => $data['id'], + 'title' => $data['subject_raw'], + 'content' => $content, + ]; + MyDumpTool::saveJson('public/'.$pico.'/'.$data['id'].'.json', $item); + $confContents[] = [ + 'id' => $item['id'], + 'title' => $data['subject_raw'], + 'cat_id' => (int) $data['cat_id'], + 'weight' => (int) $data['weight'], + 'link' => $link, + ]; + } + } + $moduleinfo = [ + 'name' => $module->get('name'), + 'dirname' => $pico, + 'message' => $moduleConfig['top_message'], + 'show_menuinmoduletop' => (int) $moduleConfig['show_menuinmoduletop'], + 'show_listasindex' => (int) $moduleConfig['show_listasindex'], + 'show_breadcrumbs' => (int) $moduleConfig['show_breadcrumbs'], + 'show_pagenavi' => (int) $moduleConfig['show_pagenavi'], + ]; + MyDumpTool::decode($moduleinfo); + $config[] = [ + 'module' => $moduleinfo, + 'categories' => $confCategories, + 'contents' => $confContents, + ]; +} diff --git a/etc/dumpXooNIps.php b/etc/dumpXooNIps.php new file mode 100644 index 0000000..5ae025b --- /dev/null +++ b/etc/dumpXooNIps.php @@ -0,0 +1,1176 @@ +prefix(); + +$table = 'xoonips_item_basic'; +if (!MyDumpTool::tableExists($table)) { + exit('xoonips module not found'.PHP_EOL); +} +MyDumpTool::makeDirectory('src/database'); +MyDumpTool::makeDirectory('src/database/assets'); +MyDumpTool::makeDirectory('public/database'); +MyDumpTool::makeDirectory('public/database/file'); + +// Recent Contents +$sql = <<< SQL +SELECT + `ib`.`item_id`, `ib`.`doi`, `ib`.`last_update_date`, + GROUP_CONCAT(DISTINCT `it`.`title` ORDER BY `it`.`title_id` ASC SEPARATOR '\n') AS `title` + FROM `${prefix}_xoonips_ranking_new_item` AS `ri` + INNER JOIN `${prefix}_xoonips_item_basic` AS `ib` ON `ri`.`item_id`=`ib`.`item_id` + INNER JOIN `${prefix}_xoonips_index_item_link` AS `iil` ON `ib`.`item_id`=`iil`.`item_id` + INNER JOIN `${prefix}_xoonips_item_title` AS `it` ON `ib`.`item_id`=`it`.`item_id` + WHERE `iil`.`certify_state`=2 + GROUP BY `ib`.`item_id` + ORDER BY `ib`.`last_update_date` DESC +SQL; +if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); +} +$ranking = []; +while ($row = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($row); + MyDumpTool::convertToInt($row, array('item_id', 'last_update_date')); + $ranking[] = $row; +} +$xoopsDB->freeRecordSet($res); +MyDumpTool::saveJson('src/database/assets/recent-contents.json', $ranking); +unset($ranking); + +// Rankings +$ranking = []; +$rankingLimit = defined('XOONIPS_RANNKING_LIMIT') ? XOONIPS_RANNKING_LIMIT : 10; +// - most accessed items +$ranking['accessed'] = []; +$sql = <<< SQL +SELECT + `ib`.`item_id`, `ib`.`doi`, + GROUP_CONCAT(DISTINCT `it`.`title` ORDER BY `it`.`title_id` ASC SEPARATOR '\n') AS `title`, + `vi`.`count` + FROM `${prefix}_xoonips_ranking_viewed_item` AS `vi` + INNER JOIN `${prefix}_xoonips_item_basic` AS `ib` ON `vi`.`item_id`=`ib`.`item_id` + INNER JOIN `${prefix}_xoonips_item_title` AS `it` ON `ib`.`item_id`=`it`.`item_id` + INNER JOIN `${prefix}_xoonips_index_item_link` AS `iil` ON `ib`.`item_id`=`iil`.`item_id` + WHERE `iil`.`certify_state`=2 + GROUP BY `ib`.`item_id` + ORDER BY `vi`.`count` DESC + LIMIT ${rankingLimit} +SQL; +if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); +} +while ($row = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($row); + MyDumpTool::convertToInt($row, array('item_id', 'count')); + $ranking['accessed'][] = $row; +} +$xoopsDB->freeRecordSet($res); +// - most accessed items +$ranking['downloaded'] = []; +$sql = <<< SQL +SELECT + `ib`.`item_id`, `ib`.`doi`, + GROUP_CONCAT(DISTINCT `it`.`title` ORDER BY `it`.`title_id` ASC SEPARATOR '\n') AS `title`, + `di`.`count` + FROM `${prefix}_xoonips_ranking_downloaded_item` AS `di` + INNER JOIN `${prefix}_xoonips_item_basic` AS `ib` ON `di`.`item_id`=`ib`.`item_id` + INNER JOIN `${prefix}_xoonips_item_title` AS `it` ON `ib`.`item_id`=`it`.`item_id` + INNER JOIN `${prefix}_xoonips_index_item_link` AS `iil` ON `ib`.`item_id`=`iil`.`item_id` + WHERE `iil`.`certify_state`=2 + GROUP BY `ib`.`item_id` + ORDER BY `di`.`count` DESC + LIMIT ${rankingLimit} +SQL; +if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); +} +while ($row = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($row); + MyDumpTool::convertToInt($row, array('item_id', 'count')); + $ranking['downloaded'][] = $row; +} +$xoopsDB->freeRecordSet($res); +// - most contributed users +$ranking['contributed'] = []; +$sql = <<< SQL +SELECT + `u`.`uid`, `u`.`uname`, `u`.`name`, COUNT(`cu`.`item_id`) AS `count` + FROM `${prefix}_xoonips_ranking_contributing_user` AS `cu` + INNER JOIN `${prefix}_users` AS `u` ON `cu`.`uid`=`u`.`uid` + GROUP BY `u`.`uid` + ORDER BY `count` DESC + LIMIT ${rankingLimit} +SQL; +if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); +} +while ($row = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($row); + MyDumpTool::convertToInt($row, array('uid', 'count')); + $ranking['contributed'][] = $row; +} +$xoopsDB->freeRecordSet($res); +// - most searched keywords +$ranking['searched'] = []; +$sql = <<< SQL +SELECT + `sk`.`keyword`, `sk`.`count` + FROM `${prefix}_xoonips_ranking_searched_keyword` AS `sk` + ORDER BY `sk`.`count` DESC + LIMIT ${rankingLimit} +SQL; +if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); +} +while ($row = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($row); + MyDumpTool::convertToInt($row, array('count')); + $ranking['searched'][] = $row; +} +$xoopsDB->freeRecordSet($res); +MyDumpTool::saveJson('src/database/assets/rankings.json', $ranking); +unset($ranking); + +// get public index with certified item count +$sql = <<< SQL +SELECT + `idx`.*, + `it`.`title`, + (SELECT COUNT(*) + FROM `${prefix}_xoonips_index_item_link` AS `iil` + INNER JOIN `${prefix}_xoonips_item_basic` AS `ib` ON `iil`.`item_id`=`ib`.`item_id` + WHERE `iil`.`index_id`=`idx`.`index_id` AND `iil`.`certify_state`=2 + ) AS `num_items` + FROM `${prefix}_xoonips_index` AS `idx` + INNER JOIN `${prefix}_xoonips_item_title` AS `it` ON `idx`.`index_id`=`it`.`item_id` + WHERE `it`.`title_id`=0 + AND `idx`.`open_level`=1 +SQL; + +$limitItems = array(); +$limitFiles = array(); + +if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); +} +$tree = array(); +$root = array(); +while ($row = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($row); + $tree[$row['index_id']] = $row; + $root[$row['parent_index_id']][$row['sort_number']] = $row['index_id']; +} +$xoopsDB->freeRecordSet($res); +foreach ($root as &$node) { + ksort($node); +} +unset($node); + +$data[] = getTreeNode($tree, $root, 3); +MyDumpTool::saveJson('src/database/assets/tree.json', $data); +unset($data, $root); + +// get simpf link data +$simpflink = parseSimPFLinkFile(); +$simpfurls = []; + +// get public items +$sql = <<< SQL +SELECT + `ib`.*, + GROUP_CONCAT(DISTINCT `it`.`title` ORDER BY `it`.`title_id` ASC SEPARATOR '\n') AS `title`, + `ity`.`display_name` AS `item_type_display_name`, `ity`.`name` AS `item_type_name`, + `u`.`uname`, `u`.`name`, `u`.`email` + FROM `${prefix}_xoonips_item_basic` AS `ib` + INNER JOIN `${prefix}_xoonips_item_title` AS `it` ON `ib`.`item_id`=`it`.`item_id` + INNER JOIN `${prefix}_xoonips_item_type` AS `ity` ON `ib`.`item_type_id`=`ity`.`item_type_id` + INNER JOIN `${prefix}_xoonips_index_item_link` AS `iil` ON `ib`.`item_id`=`iil`.`item_id` + INNER JOIN `${prefix}_xoonips_index` AS `idx` ON `iil`.`index_id`=`idx`.`index_id` + LEFT JOIN `${prefix}_users` AS `u` ON `ib`.`uid`=`u`.`uid` + WHERE `ity`.`display_name` != 'Index' + AND `iil`.`certify_state`=2 + AND `idx`.`open_level`=1 + GROUP BY `ib`.`item_id` + ORDER BY `ib`.`item_id` ASC +SQL; + +if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); +} +$items = array(); +while ($row = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($row); + MyDumpTool::convertToInt($row, array('item_id', 'item_type_id', 'uid', 'last_update_date', 'creation_date', 'publication_year', 'publication_month', 'publication_mday')); + $row['index'] = getIndexes($tree, $row['item_id']); + if (0 === count($row['index'])) { + // no public indexes found. + continue; + } + $row['changelog'] = getChangeLogs($row['item_id']); + $row['related_to'] = getRelatedTo($row['item_id']); + $row['keyword'] = getKeyword($row['item_id']); + $row['file'] = getFile($row['item_id']); + switch ($row['item_type_name']) { + case 'xnpbinder': + appendBinderInfo($row); + break; + case 'xnpbook': + appendBookInfo($row); + break; + case 'xnpconference': + appendConferenceInfo($row); + break; + case 'xnpdata': + appendDataInfo($row); + break; + case 'xnpfiles': + appendFilesInfo($row); + break; + case 'xnpmemo': + appendMemoInfo($row); + break; + case 'xnpmodel': + appendModelInfo($row); + break; + case 'xnppaper': + appendPaperInfo($row); + break; + case 'xnppresentation': + appendPresentationInfo($row); + break; + case 'xnpsimulator': + appendSimulatorInfo($row); + break; + case 'xnpstimulus': + appendStimulusInfo($row); + break; + case 'xnptool': + appendToolInfo($row); + break; + case 'xnpurl': + appendUrlInfo($row); + break; + case 'xnpnimgcenter': + appendNimgcenterInfo($row); + break; + default: + exit('Unsupported item type: '.$row['item_type_name']); + } + if (isset($row['attachment_dl_limit']) && $row['attachment_dl_limit']) { + $found = false; + foreach ($row['file'] as $file) { + if ('preview' !== $file['file_type_name']) { + $limitFiles[] = $file['file_id']; + $found = true; + } + } + if ($found) { + $limitItems[] = array( + 'uname' => $row['uname'], + 'name' => $row['name'], + 'email' => $row['email'], + 'item_id' => $row['item_id'], + 'doi' => $row['doi'], + ); + } + } + MyDumpTool::dropColumn($row, ['email', 'item_type_id']); + if (isset($row['rights']) && isset($row['use_cc']) && isset($row['cc_commercial_use']) && isset($row['cc_modification']) && 1 == $row['use_cc']) { + $label = 'Creative Commons Attribution'; + if (0 == $row['cc_commercial_use']) { + $label .= '-NonCommercial'; + } + switch ($row['cc_modification']) { + case 0: + $label .= '-NoDerivatives'; + break; + case 1: + $label .= '-ShareAlike'; + break; + } + $label .= ' 4.0 International License.'; + $row['rights'] = $label; + } + $items[] = $row; + + $simpfurl = ''; + if ('' != $row['doi'] && isset($simpflink['id'][$row['doi']])) { + $simpfurl = $simpflink['id'][$row['doi']]; + } elseif (isset($simpflink['item_id'][$row['item_id']])) { + $simpfurl = $simpflink['item_id'][$row['item_id']]; + } + if ('' !== $simpfurl) { + $simpfurls[] = [ + 'id' => $row['item_id'], + 'url' => $simpfurl, + ]; + } +} +$xoopsDB->freeRecordSet($res); +MyDumpTool::saveJson('public/database/items.json', $items); +if (!empty($simpfurls)) { + MyDumpTool::saveJson('src/database/assets/simpf-links.json', $simpfurls); +} + +$fp = fopen(MYDUMPTOOL_OUTPUTDIR.'/dl-limit-items.csv', 'w'); +foreach ($limitItems as $row) { + $data = array( + $row['item_id'], + $row['uname'], + $row['name'], + $row['email'], + getItemUrl($row), + ); + fputcsv($fp, $data); +} +fclose($fp); + +// get files +$xconfig_handler = xoonips_getormhandler('xoonips', 'config'); +$fileutil = xoonips_getutility('file'); + +$basePath = $xconfig_handler->getValue('upload_dir'); +$sql = <<< SQL +SELECT + `f`.`file_id`, `f`.`item_id`, `f`.`original_file_name`, + `ft`.`name` AS `file_type_name` + FROM `${prefix}_xoonips_file` AS `f` + INNER JOIN `${prefix}_xoonips_file_type` AS `ft` ON `f`.`file_type_id`=`ft`.`file_type_id` + INNER JOIN `${prefix}_xoonips_index_item_link` AS `iil` ON `f`.`item_id`=`iil`.`item_id` + INNER JOIN `${prefix}_xoonips_index` AS `idx` ON `iil`.`index_id`=`idx`.`index_id` + WHERE `f`.`is_deleted`=0 + AND `ft`.`name` NOT IN('readme' , 'license', 'rights') + AND `iil`.`certify_state`=2 + AND `idx`.`open_level`=1 + GROUP BY `f`.`file_id` + ORDER BY `f`.`file_id` ASC +SQL; + +if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); +} +$filesDir = MYDUMPTOOL_OUTPUTDIR.'/public/database/file'; +while ($row = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($row); + MyDumpTool::convertToInt($row, array('file_id', 'item_id')); + $file_id = $row['file_id']; + $item_id = $row['item_id']; + $file_name = $row['original_file_name']; + $file_type = $row['file_type_name']; + if (in_array($file_id, $limitFiles)) { + echo "download limit file found.. skip to copy.. item_id:$item_id, file_id:$file_id".PHP_EOL; + continue; + } + $file_dir = $filesDir.'/'.$file_id; + $src_file = $basePath.'/'.$file_id; + if (!is_dir($file_dir)) { + @mkdir($file_dir); + } + //if (!file_exists($file_dir.'/'.$file_name)) { + if (!MyDumpTool::fileCopy($src_file, $file_dir.'/'.$file_name)) { + echo 'failed to copy file: '.$basePath.'/'.$file_id.PHP_EOL; + } + $htaccess = $file_dir.'/.htaccess'; + $xfilename = str_replace(' ', '\\ ', $file_name); + $data = "RewriteEngine On\nRewriteBase /database/file/$file_id\nRewriteCond %{REQUEST_FILENAME} !-f\nRewriteRule .* $xfilename [R=301,L]\n"; + file_put_contents($htaccess, $data); + //} + if ('preview' == $file_type) { + $thumbnail_file = $file_dir.'.png'; + if (!file_exists($thumbnail_file)) { + $mimetype = $fileutil->get_mimetype($src_file, $file_name); + $thumbnail = $fileutil->get_thumbnail($src_file, $mimetype); + if (null !== $thumbnail) { + file_put_contents($thumbnail_file, $thumbnail); + } else { + createThumbnail($src_file, $mimetype, $thumbnail_file); + } + } + } +} +$xoopsDB->freeRecordSet($res); + +// functions + +function getItemUrl($row) +{ + $url = XOONIPS_URL.'/detail.php?'; + if ('' != $row['doi']) { + $url .= XNP_CONFIG_DOI_FIELD_PARAM_NAME.'='.$row['doi']; + } else { + $url .= 'item_id='.$row['item_id']; + } + + return $url; +} + +function getTreeNode($tree, $root, $index_id) +{ + $children = array(); + if (isset($root[$index_id])) { + foreach ($root[$index_id] as $child_index_id) { + $children[] = getTreeNode($tree, $root, $child_index_id); + } + } + + return array( + 'id' => (int) $tree[$index_id]['index_id'], + 'title' => $tree[$index_id]['title'], + 'num_of_items' => (int) $tree[$index_id]['num_items'], + 'children' => $children, + ); +} + +function getIndexes($tree, $item_id) +{ + global $xoopsDB; + $prefix = $xoopsDB->prefix(); + $sql = <<< SQL +SELECT + `iil`.`index_id` + FROM `${prefix}_xoonips_index_item_link` AS `iil` + WHERE `iil`.`item_id`=$item_id + ORDER BY `iil`.`index_id` +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + $indexes = array(); + while ($row = $xoopsDB->fetchArray($res)) { + $index_id = $row['index_id']; + if (isset($tree[$index_id])) { + $idxes = array(); + $idxes[] = $tree[$index_id]['title']; + $parent_id = $tree[$index_id]['parent_index_id']; + while (1 != $parent_id) { + $idxes[] = $tree[$parent_id]['title']; + $parent_id = $tree[$parent_id]['parent_index_id']; + } + $idxes[] = ''; + $indexes[] = array( + 'index_id' => (int) $index_id, + 'title' => trim(implode(' / ', array_reverse($idxes))), + ); + } + } + $xoopsDB->freeRecordSet($res); + + return $indexes; +} + +function getChangeLogs($item_id) +{ + global $xoopsDB; + $prefix = $xoopsDB->prefix(); + $sql = <<< SQL +SELECT `log_date`, `log` + FROM `${prefix}_xoonips_changelog` + WHERE `item_id`=$item_id + ORDER BY `log_date` DESC +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + $ret = array(); + while ($row = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($row); + MyDumpTool::convertToInt($row, array('log_date')); + $ret[] = $row; + } + $xoopsDB->freeRecordSet($res); + + return $ret; +} + +function getRelatedTo($item_id) +{ + global $xoopsDB; + $prefix = $xoopsDB->prefix(); + $sql = <<< SQL +SELECT `item_id` + FROM `${prefix}_xoonips_related_to` + WHERE `parent_id`=$item_id +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + $ret = array(); + while ($row = $xoopsDB->fetchArray($res)) { + $ret[] = (int) $row['item_id']; + } + $xoopsDB->freeRecordSet($res); + + return $ret; +} + +function getKeyword($item_id) +{ + global $xoopsDB; + $prefix = $xoopsDB->prefix(); + $sql = <<< SQL +SELECT * + FROM `${prefix}_xoonips_item_keyword` + WHERE `item_id`=$item_id + ORDER BY `keyword_id` ASC +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + $ret = array(); + while ($row = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($row); + $ret[] = $row['keyword']; + } + $xoopsDB->freeRecordSet($res); + + return $ret; +} + +function getFile($item_id) +{ + global $xoopsDB; + $prefix = $xoopsDB->prefix(); + $sql = <<< SQL +SELECT `f`.`file_id`, `f`.`original_file_name`, `f`.`mime_type`, `f`.`file_size`, `f`.`caption`, `f`.`timestamp`, + `ft`.`name` AS `file_type_name`, `ft`.`display_name` AS `file_type_display_name` + FROM `${prefix}_xoonips_file` AS `f` + INNER JOIN `${prefix}_xoonips_file_type` AS `ft` ON `f`.`file_type_id`=`ft`.`file_type_id` + WHERE `item_id`=$item_id + AND `is_deleted`=0 + ORDER BY `ft`.`name` ASC +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + $ret = array(); + while ($row = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($row); + MyDumpTool::convertToInt($row, array('file_id', 'file_size')); + $ret[] = $row; + } + $xoopsDB->freeRecordSet($res); + + return $ret; +} + +function appendBinderInfo(&$row) +{ + global $xoopsDB; + $prefix = $xoopsDB->prefix(); + $item_id = $row['item_id']; + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnpbinder_item_detail` + WHERE `binder_id`=$item_id +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + while ($detail = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($detail); + MyDumpTool::convertToInt($detail, array('binder_id')); + MyDumpTool::dropColumn($detail, ['binder_id']); + $row += $detail; + } + $xoopsDB->freeRecordSet($res); + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnpbinder_binder_item_link` + WHERE `binder_id`=$item_id + ORDER BY `item_id` ASC +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + $row['item_link'] = array(); + while ($row2 = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($row2); + $row['item_link'][] = (int) $row2['item_id']; + } + $xoopsDB->freeRecordSet($res); +} + +function appendBookInfo(&$row) +{ + global $xoopsDB; + $prefix = $xoopsDB->prefix(); + $item_id = $row['item_id']; + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnpbook_item_detail` + WHERE `book_id`=$item_id +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + while ($detail = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($detail); + MyDumpTool::convertToInt($detail, array('book_id', 'attachment_dl_limit', 'attachment_dl_notify')); + MyDumpTool::convertToInt($detail, array('volume', 'number')); // for CBSN + MyDumpTool::dropColumn($detail, ['book_id']); + $row += $detail; + } + $xoopsDB->freeRecordSet($res); + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnpbook_author` + WHERE `book_id`=$item_id + ORDER BY `author_order` ASC +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + $row['author'] = array(); + while ($author = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($author); + $row['author'][] = $author['author']; + } + $xoopsDB->freeRecordSet($res); +} + +function appendConferenceInfo(&$row) +{ + global $xoopsDB; + $prefix = $xoopsDB->prefix(); + $item_id = $row['item_id']; + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnpconference_item_detail` + WHERE `conference_id`=$item_id +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + while ($detail = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($detail); + MyDumpTool::convertToInt($detail, array('conference_id', 'conference_from_year', 'conference_from_month', 'conference_from_mday', 'conference_to_year', 'conference_to_month', 'conference_to_mday', 'attachment_dl_limit', 'attachment_dl_notify')); + MyDumpTool::dropColumn($detail, ['conference_id']); + $row += $detail; + } + $xoopsDB->freeRecordSet($res); + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnpconference_author` + WHERE `conference_id`=$item_id + ORDER BY `author_order` ASC +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + $row['author'] = array(); + while ($author = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($author); + $row['author'][] = $author['author']; + } + $xoopsDB->freeRecordSet($res); +} + +function appendDataInfo(&$row) +{ + global $xoopsDB; + $prefix = $xoopsDB->prefix(); + $item_id = $row['item_id']; + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnpdata_item_detail` + WHERE `data_id`=$item_id +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + while ($detail = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($detail); + MyDumpTool::convertToInt($detail, array('data_id', 'use_cc', 'cc_commercial_use', 'cc_modification', 'attachment_dl_limit', 'attachment_dl_notify')); + MyDumpTool::dropColumn($detail, ['data_id']); + $row += $detail; + } + $xoopsDB->freeRecordSet($res); + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnpdata_experimenter` + WHERE `data_id`=$item_id + ORDER BY `experimenter_order` ASC +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + $row['experimenter'] = array(); + while ($author = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($author); + $row['experimenter'][] = $author['experimenter']; + } + $xoopsDB->freeRecordSet($res); +} + +function appendFilesInfo(&$row) +{ + global $xoopsDB; + $prefix = $xoopsDB->prefix(); + $item_id = $row['item_id']; + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnpfiles_item_detail` + WHERE `files_id`=$item_id +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + while ($detail = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($detail); + MyDumpTool::convertToInt($detail, array('files_id')); + MyDumpTool::dropColumn($detail, ['files_id']); + $row += $detail; + } + $xoopsDB->freeRecordSet($res); +} + +function appendMemoInfo(&$row) +{ + global $xoopsDB; + $prefix = $xoopsDB->prefix(); + $item_id = $row['item_id']; + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnpmemo_item_detail` + WHERE `memo_id`=$item_id +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + while ($detail = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($detail); + MyDumpTool::convertToInt($detail, array('memo_id')); + MyDumpTool::dropColumn($detail, ['memo_id']); + $row += $detail; + } + $xoopsDB->freeRecordSet($res); +} + +function appendModelInfo(&$row) +{ + global $xoopsDB; + $prefix = $xoopsDB->prefix(); + $item_id = $row['item_id']; + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnpmodel_item_detail` + WHERE `model_id`=$item_id +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + while ($detail = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($detail); + MyDumpTool::convertToInt($detail, array('model_id', 'use_cc', 'cc_commercial_use', 'cc_modification', 'attachment_dl_limit', 'attachment_dl_notify')); + MyDumpTool::dropColumn($detail, ['model_id']); + $row += $detail; + } + $xoopsDB->freeRecordSet($res); + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnpmodel_creator` + WHERE `model_id`=$item_id + ORDER BY `creator_order` ASC +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + $row['creator'] = array(); + while ($author = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($author); + $row['creator'][] = $author['creator']; + } + $xoopsDB->freeRecordSet($res); +} + +function appendPaperInfo(&$row) +{ + global $xoopsDB; + $prefix = $xoopsDB->prefix(); + $item_id = $row['item_id']; + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnppaper_item_detail` + WHERE `paper_id`=$item_id +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + while ($detail = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($detail); + MyDumpTool::convertToInt($detail, array('paper_id', 'volume', 'number')); + MyDumpTool::dropColumn($detail, ['paper_id']); + $row += $detail; + } + $xoopsDB->freeRecordSet($res); + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnppaper_author` + WHERE `paper_id`=$item_id + ORDER BY `author_order` ASC +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + $row['author'] = array(); + while ($author = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($author); + $row['author'][] = $author['author']; + } + $xoopsDB->freeRecordSet($res); +} + +function appendPresentationInfo(&$row) +{ + global $xoopsDB; + $prefix = $xoopsDB->prefix(); + $item_id = $row['item_id']; + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnppresentation_item_detail` + WHERE `presentation_id`=$item_id +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + while ($detail = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($detail); + MyDumpTool::convertToInt($detail, array('presentation_id', 'use_cc', 'cc_commercial_use', 'cc_modification', 'attachment_dl_limit', 'attachment_dl_notify')); + MyDumpTool::dropColumn($detail, ['presentation_id']); + $row += $detail; + } + $xoopsDB->freeRecordSet($res); + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnppresentation_creator` + WHERE `presentation_id`=$item_id + ORDER BY `creator_order` ASC +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + $row['creator'] = array(); + while ($author = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($author); + $row['creator'][] = $author['creator']; + } + $xoopsDB->freeRecordSet($res); +} + +function appendSimulatorInfo(&$row) +{ + global $xoopsDB; + $prefix = $xoopsDB->prefix(); + $item_id = $row['item_id']; + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnpsimulator_item_detail` + WHERE `simulator_id`=$item_id +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + while ($detail = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($detail); + MyDumpTool::convertToInt($detail, array('simulator_id', 'use_cc', 'cc_commercial_use', 'cc_modification', 'attachment_dl_limit', 'attachment_dl_notify')); + MyDumpTool::dropColumn($detail, ['simulator_id']); + $row += $detail; + } + $xoopsDB->freeRecordSet($res); + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnpsimulator_developer` + WHERE `simulator_id`=$item_id + ORDER BY `developer_order` ASC +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + $row['developer'] = array(); + while ($author = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($author); + $row['developer'][] = $author['developer']; + } + $xoopsDB->freeRecordSet($res); +} + +function appendStimulusInfo(&$row) +{ + global $xoopsDB; + $prefix = $xoopsDB->prefix(); + $item_id = $row['item_id']; + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnpstimulus_item_detail` + WHERE `stimulus_id`=$item_id +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + while ($detail = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($detail); + MyDumpTool::convertToInt($detail, array('stimulus_id', 'use_cc', 'cc_commercial_use', 'cc_modification', 'attachment_dl_limit', 'attachment_dl_notify')); + MyDumpTool::dropColumn($detail, ['stimulus_id']); + $row += $detail; + } + $xoopsDB->freeRecordSet($res); + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnpstimulus_developer` + WHERE `stimulus_id`=$item_id + ORDER BY `developer_order` ASC +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + $row['developer'] = array(); + while ($author = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($author); + $row['developer'][] = $author['developer']; + } + $xoopsDB->freeRecordSet($res); +} + +function appendToolInfo(&$row) +{ + global $xoopsDB; + $prefix = $xoopsDB->prefix(); + $item_id = $row['item_id']; + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnptool_item_detail` + WHERE `tool_id`=$item_id +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + while ($detail = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($detail); + MyDumpTool::convertToInt($detail, array('tool_id', 'use_cc', 'cc_commercial_use', 'cc_modification', 'attachment_dl_limit', 'attachment_dl_notify')); + MyDumpTool::dropColumn($detail, ['tool_id']); + $row += $detail; + } + $xoopsDB->freeRecordSet($res); + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnptool_developer` + WHERE `tool_id`=$item_id + ORDER BY `developer_order` ASC +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + $row['developer'] = array(); + while ($author = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($author); + $row['developer'][] = $author['developer']; + } + $xoopsDB->freeRecordSet($res); +} + +function appendUrlInfo(&$row) +{ + global $xoopsDB; + $prefix = $xoopsDB->prefix(); + $item_id = $row['item_id']; + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnpurl_item_detail` + WHERE `url_id`=$item_id +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + while ($detail = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($detail); + MyDumpTool::convertToInt($detail, array('url_id', 'url_count')); + MyDumpTool::dropColumn($detail, ['url_id']); + $row += $detail; + } + $xoopsDB->freeRecordSet($res); +} + +function appendNimgcenterInfo(&$row) +{ + global $xoopsDB; + $prefix = $xoopsDB->prefix(); + $item_id = $row['item_id']; + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnpnimgcenter_item_detail` + WHERE `nimgcenter_id`=$item_id +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + while ($detail = $xoopsDB->fetchArray($res)) { + MyDumpTool::decode($detail); + $detail['coord_type_name'] = (0 === $detail['coord_type']) ? 'Talairach' : 'MNI'; + MyDumpTool::dropColumn($detail, ['nimgcenter_id']); + $row += $detail; + } + $xoopsDB->freeRecordSet($res); + $sql = <<< SQL +SELECT * + FROM `${prefix}_xnpnimgcenter_talairach_list` + WHERE `nimgcenter_id`=$item_id +SQL; + if (!($res = $xoopsDB->query($sql))) { + var_dump($xoopsDB); + exit(); + } + $row['coordinate'] = array(); + while ($t = $xoopsDB->fetchArray($res)) { + $row['coordinate'][] = $t; + } + $xoopsDB->freeRecordSet($res); +} + +function createThumbnail($inputFile, $mime_type, $outputFile) +{ + $finfo = finfo_open(FILEINFO_NONE); + $label = finfo_file($finfo, $inputFile); + finfo_close($finfo); + if (preg_match('/^([^\\/]*)\\/(.*)$/', $mime_type, $matches)) { + if ('audio' == $matches[1]) { + $img_type = 'audio'; + } elseif ('image' == $matches[1]) { + $img_type = 'image'; + } elseif ('video' == $matches[1]) { + $img_type = 'video'; + } elseif ('text' == $matches[1]) { + $img_type = 'text'; + } elseif ('application' == $matches[1]) { + $text_types = array('pdf', 'xml', 'msword', 'vnd.ms-excel'); + $image_types = array('vnd.ms-powerpoint', 'postscript'); + $audio_types = array('vnd.rn-realmedia'); + if (in_array($matches[2], $text_types)) { + $img_type = 'text'; + } elseif (in_array($matches[2], $audio_types)) { + $img_type = 'audio'; + } elseif (in_array($matches[2], $image_types)) { + $img_type = 'image'; + } else { + $img_type = 'application'; + } + } else { + $img_type = 'unknown'; + } + } else { + $img_type = 'unknown'; + } + $img_file = XOOPS_ROOT_PATH.'/modules/xoonips/images/thumbnail_'.$img_type.'.png'; + // create image resource + $w = 100; + $h = 100; + $im = imagecreatetruecolor($w, $h); + // label setting + $f = 2; + // font number + $lp = 5; + // label padding + $fw = imagefontwidth($f); + // font width + $fh = imagefontheight($f); + // font height + $fmaxlen = ($w - $lp * 2) / $fw; + // max label length + $labels = explode(',', $label); + $label = $labels[0]; + $llen = strlen($label); + if ($llen > $fmaxlen) { + $label = substr($label, 0, $fmaxlen - 3); + $label .= '...'; + $llen = strlen($label); + } + $lx = ($w - $llen * $fw) / 2; + $ly = $h - $fh - $lp; + // change alpha attributes and create transparent color + imageantialias($im, true); + imagealphablending($im, false); + imagesavealpha($im, true); + $transparent = imagecolorallocatealpha($im, 255, 255, 255, 0); + $col_white = imagecolorallocate($im, 255, 255, 255); + $col_gray = imagecolorallocate($im, 127, 127, 127); + $col_black = imagecolorallocate($im, 0, 0, 0); + // fill all area with transparent color + imagefill($im, 0, 0, $col_white); + imagealphablending($im, true); + $imicon = imagecreatefrompng($img_file); + imagecopy($im, $imicon, $w / 2 - 48 / 2, $h / 2 - 48 / 2, 0, 0, 48, 48); + imagepolygon($im, array(0, 0, $w - 1, 0, $w - 1, $h - 1, 0, $h - 1), 4, $col_gray); + if (0 != strlen($label)) { + imagestring($im, $f, $lx, $ly, $label, $col_black); + } + imagepng($im, $outputFile); + imagedestroy($imicon); + imagedestroy($im); + + return true; +} + +function parseSimPFLinkFile() +{ + global $XOONIPS_SIMPF_LINKFILE; + $xoops_url_path = parse_url(XOOPS_URL, PHP_URL_PATH); + $ret = []; + if (isset($XOONIPS_SIMPF_LINKFILE) && file_exists($XOONIPS_SIMPF_LINKFILE)) { + $lines = file($XOONIPS_SIMPF_LINKFILE); + foreach ($lines as $line) { + list($pfname, $pfurl, $simpfurl) = explode(',', $line); + if (preg_match('/^'.preg_quote(XOOPS_URL, '/').'/', $pfurl)) { + $pUrl = parse_url($pfurl); + if ($pUrl['path'] != $xoops_url_path.'/modules/xoonips/detail.php') { + echo 'not xoonips url found in simpf link file. URL:'.$pfurl.PHP_EOL; + continue; + } + if (preg_match('/(?:^|&)(id|item_id)=([^$&]+)/', $pUrl['query'], $matches)) { + $key = $matches[1]; + $value = $matches[2]; + $ret[$key][$value] = trim($simpfurl); + } + } + } + } + + return $ret; +} diff --git a/etc/fixMediaWikiDumpData.php b/etc/fixMediaWikiDumpData.php new file mode 100644 index 0000000..030eb21 --- /dev/null +++ b/etc/fixMediaWikiDumpData.php @@ -0,0 +1,180 @@ + $data['title'], + 'text' => $text, + ]; + file_put_contents(__DIR__.'/data/public/mediawiki/contents/'.$content['id'].'.json', json_encode($data2, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)); +} + +class MyUtil +{ + public static function fixHtml($text, $revid) + { + $text = preg_replace('/
    .+<\/div>/Us', '', $text); + $text = preg_replace_callback('/(.+)<\/a>/Us', function ($m) { + $fpath = MyUtil::getImagePath('/mediawiki/images', $m[1]); + + return ''.$m[2].''; + }, $text); + $text = preg_replace_callback('/(?:[^/Us', function ($m) { + return ''.$m[3].''; + }, $text); + $text = preg_replace_callback('/(?:[^/Us', function ($m) { + $bpath = 'thumb/'.$m[1]; + MyUtil::makedir(DEST_IMAGE_DIR.'/'.$bpath); + $bpath .= '/'.$m[2]; + MyUtil::makedir(DEST_IMAGE_DIR.'/'.$bpath); + $bpath_ = $bpath.'/'.$m[3]; + $bpath .= '/'.urldecode($m[3]); + MyUtil::makedir(DEST_IMAGE_DIR.'/'.$bpath); + $fpath_ = $bpath_.'/'.$m[4]; + $fpath = $bpath.'/'.urldecode($m[4]); + MyUtil::fileCopy(IMAGE_DIR.'/'.$fpath, DEST_IMAGE_DIR.'/'.$fpath); + $srcset = []; + foreach (explode(', ', $m[7]) as $src) { + if (preg_match('/^https?:\/\/dynamicbrain\.neuroinf\.jp\/uploads\/mediawiki\/thumb\/(.)\/(..)\/([^\/]+)\/([^ ]+) (.+)$/Us', trim($src), $sm)) { + $sfpath_ = $bpath_.'/'.$sm[4]; + $sfpath = $bpath.'/'.urldecode($sm[4]); + MyUtil::fileCopy(IMAGE_DIR.'/'.$sfpath, DEST_IMAGE_DIR.'/'.$sfpath); + $srcset[] = '/mediawiki/images/'.$sfpath_.' '.$sm[5]; + } + } + + return ''.$m[3].''; + }, $text); + $text = preg_replace_callback('/(.+)<\/a>/Us', function ($m) { + parse_str(htmlspecialchars_decode($m[2], ENT_QUOTES), $params); + $url = ''; + switch ($m[1]) { + case 'detail.php': + if (isset($params['item_id'])) { + $url = 'item/'.$params['item_id']; + } elseif (isset($params['id'])) { + $url = 'item/id/'.$params['id']; + } else { + var_dump($m); + exit('Unexpected parameter found..'); + } + break; + case 'itemselect.php': + if (!isset($params['op'])) { + var_dump($m); + exit('Unexpected url found..'); + break; + } + switch ($params['op']) { + case 'quicksearch': + if (!isset($params['keyword'])) { + var_dump($m); + exit('Unexpected url found.. parameter keyword not found'); + break; + } + if (!isset($params['search_itemtype'])) { + var_dump($m); + exit('Unexpected url found.. parameter search_itemtype not found'); + break; + } + $url = 'search?keyword='.$params['keyword'].'&type='.preg_replace('/^xnp/', '', $params['search_itemtype']); + break; + default: + var_dump($m); + exit('not impremented yet..'); + break; + } + break; + default: + var_dump($m); + exit('not impremented yet..'); + break; + } + + return ''.$m[3].''; + }, $text); + $text = preg_replace_callback('//Us', function ($m) { + $fpath = 'math/'.$m[1]; + MyUtil::makedir(DEST_IMAGE_DIR.'/'.$fpath); + $fpath .= '/'.$m[2]; + MyUtil::makedir(DEST_IMAGE_DIR.'/'.$fpath); + $fpath .= '/'.$m[3]; + MyUtil::makedir(DEST_IMAGE_DIR.'/'.$fpath); + $fpath .= '/'.$m[4]; + MyUtil::fileCopy(IMAGE_DIR.'/'.$fpath, DEST_IMAGE_DIR.'/'.$fpath); + + return ''.$m[4].''; + }, $text); + $text = preg_replace('/

    \s*(.*)\s*<\/p>/Us', '

    \1

    ', $text); + $text = preg_replace_callback('/href="(?:https?:\/\/dynamicbrain\.neuroinf\.jp)?\/modules\/mediawiki\/(?:index.php\/)?([^"]+)"/Us', function ($m) { + return 'href="/mediawiki/'.urlencode(str_replace(' ', '_', $m[1])).'"'; + }, $text); + $text = preg_replace_callback('//Us', function ($m) { + $fpath = '/'.$m[1]; + MyUtil::makedir(DEST_IMAGE_DIR.'/'.$fpath); + $fpath .= '/'.$m[2]; + MyUtil::makedir(DEST_IMAGE_DIR.'/'.$fpath); + $fpath_ = $fpath.'/'.$m[3]; + $fpath .= '/'.urldecode($m[3]); + MyUtil::fileCopy(IMAGE_DIR.'/'.$fpath, DEST_IMAGE_DIR.'/'.$fpath); + + return ''; + }, $text); + $text = preg_replace('/(.+)<\/a>/Us', '\1', $text); + $text = preg_replace('/href="https?:\/\/dynamicbrain\.neuroinf\.jp\/hetero/Us', 'href="/hetero', $text); + $text = preg_replace('/href="https?:\/\/dynamicbrain\.neuroinf\.jp\/modules\/hackathon\//Us', 'href="/hackathon/', $text); + $text = preg_replace('/href="https?:\/\/dynamicbrain\.neuroinf\.jp\/conferences\//Us', 'href="/conferences/', $text); + $text = preg_replace('/href="https?:\/\/dynamicbrain\.neuroinf\.jp\/modules\/documents\/(.*)"/Us', 'href="/documents/\1"', $text); + $text = preg_replace('/https?:\/\/dynamicbrain\.neuroinf\.jp\/modules\/hackathon\//Us', 'https://dynamicbrain.neuroinf.jp/hackathon/', $text); + $text = preg_replace('/]*)>(\s)*]*)>/Us', '\2', $text); + $text = preg_replace('/<\/tr>(\s*)<\/table>/s', '\1', $text); + $text = trim($text); + if (preg_match('/https?:\/\/dynamicbrain\.neuroinf\.jp/', $text)) { + $okids = [2614]; + if (!in_array($revid, $okids)) { + echo $text.PHP_EOL; + die('dynamicbrain internal url link still found: '.$revid.PHP_EOL); + } + } + + return $text; + } + + public static function makedir($path) + { + if (is_dir($path)) { + return true; + } + if (false === @mkdir($path)) { + exit('Failed to create directroy: '.$path.PHP_EOL); + } + + return true; + } + + public static function getImagePath($basedir, $fname) + { + $hash = md5($fname); + + return $basedir.'/'.substr($hash, 0, 1).'/'.substr($hash, 0, 2).'/'.$fname; + } + + public static function fileCopy($from, $to) + { + system('rsync -aq '.escapeshellarg($from).' '.escapeshellarg($to), $ret); + if (0 !== $ret) { + exit('Failed to copy file: '.$from.' -> '.$to.PHP_EOL); + } + + return 0 === $ret; + } +} diff --git a/etc/simpflink.csv b/etc/simpflink.csv new file mode 100644 index 0000000..86cd994 --- /dev/null +++ b/etc/simpflink.csv @@ -0,0 +1,465 @@ +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=6045,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=25 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=909,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=27 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=1648,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=28 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=913,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=29 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=1623,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=30 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=1620,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=32 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=896,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=33 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=2434,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=34 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=2441,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=35 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=5307,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=37 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?id=943,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=38 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=403,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=39 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=398,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=40 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=350,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=41 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=366,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=43 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=370,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=44 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=361,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=45 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?id=4449054b,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=46 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=6110,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=47 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?id=7252867b,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=48 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=6105,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=49 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=2861,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=50 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?id=16625198b,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=51 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=6422,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=52 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?id=19281836b,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=53 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?id=7941380b,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=54 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=6448,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=55 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=6106,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=56 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1027,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=57 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1030,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=58 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1031,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=59 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1033,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=61 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1034,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=62 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1035,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=63 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1036,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=64 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1037,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=65 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1038,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=66 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1041,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=67 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1042,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=68 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1043,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=69 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1044,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=70 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1045,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=71 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1046,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=72 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1047,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=73 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1048,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=74 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1051,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=76 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1052,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=77 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1054,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=78 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1056,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=79 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1057,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=80 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1059,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=81 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1060,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=82 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1061,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=83 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1062,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=84 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1064,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=85 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1065,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=86 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1066,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=87 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1067,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=114 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1068,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=116 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1069,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=117 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1071,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=119 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1073,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=121 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1076,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=124 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1077,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=125 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1078,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=126 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1079,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=127 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=296,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=128 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=5586,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=129 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=297,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=130 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1080,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=131 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1081,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=132 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1082,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=133 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1084,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=134 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1085,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=135 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1086,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=136 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1087,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=137 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1088,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=138 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1089,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=139 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1098,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=140 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1099,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=141 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1100,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=142 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1101,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=143 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1102,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=144 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1103,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=145 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1105,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=146 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1106,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=147 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1107,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=148 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1108,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=149 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1109,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=150 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1110,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=151 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1111,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=152 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1112,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=153 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1113,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=154 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1114,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=155 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1115,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=156 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1119,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=159 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1120,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=160 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1121,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=161 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1122,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=162 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1123,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=163 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1124,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=164 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1125,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=165 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1127,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=167 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1128,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=168 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1129,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=169 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1130,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=170 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1131,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=171 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1132,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=172 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1134,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=174 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1135,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=175 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1136,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=176 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1137,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=177 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1138,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=178 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1139,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=179 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1140,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=180 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1141,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=181 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1142,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=182 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1143,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=183 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1144,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=184 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1146,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=186 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1147,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=187 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1148,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=188 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1149,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=189 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1150,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=190 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1152,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=192 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1153,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=193 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1154,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=194 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1156,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=195 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1157,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=196 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1159,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=198 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1160,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=199 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1161,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=200 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1162,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=201 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1163,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=202 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1164,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=203 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1165,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=204 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1166,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=205 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1167,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=206 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1168,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=207 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1169,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=208 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1170,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=209 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1171,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=210 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1173,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=212 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1174,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=213 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1175,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=214 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1176,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=215 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1177,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=216 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1178,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=217 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1179,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=218 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1180,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=219 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1181,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=220 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1182,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=221 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1183,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=222 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1184,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=223 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1185,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=224 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1186,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=225 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1187,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=226 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1188,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=227 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1189,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=228 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1190,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=229 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1191,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=230 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1192,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=231 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1193,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=232 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?id=15929656d,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=233 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=376,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=234 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=298,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=235 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=1629,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=236 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=1647,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=237 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1209,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=239 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1210,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=240 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1211,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=241 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1212,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=242 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1213,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=243 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1214,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=244 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1215,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=245 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1216,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=246 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1218,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=248 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1219,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=249 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1220,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=250 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1222,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=251 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1223,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=252 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1224,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=253 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1225,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=254 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1226,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=255 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1227,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=256 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1228,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=257 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1230,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=258 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1231,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=259 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1232,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=260 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1233,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=261 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1234,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=262 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1235,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=263 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1236,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=264 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1237,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=265 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1238,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=266 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1239,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=267 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1240,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=268 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1241,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=269 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1242,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=270 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1243,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=271 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1244,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=272 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1245,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=273 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1246,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=274 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1247,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=275 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1248,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=276 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1251,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=279 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1252,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=280 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1255,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=281 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1256,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=282 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1257,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=283 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1258,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=284 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1262,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=286 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1263,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=287 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1264,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=288 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1265,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=289 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1266,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=290 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1268,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=292 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1269,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=293 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1270,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=294 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1271,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=295 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1272,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=296 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1273,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=297 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1278,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=302 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1279,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=303 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1280,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=304 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1281,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=305 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1282,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=306 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1283,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=307 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1284,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=308 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1285,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=309 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1286,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=310 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1287,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=311 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1288,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=312 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1289,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=313 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1291,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=315 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1292,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=316 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1293,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=317 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1294,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=318 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1295,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=319 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1296,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=320 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1298,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=322 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1299,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=323 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1300,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=324 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1302,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=326 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1306,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=330 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1312,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=336 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1313,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=337 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1314,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=338 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1315,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=339 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=162,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=341 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=5936,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=342 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/558/weaverWearne06.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=360 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?id=4449054c,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=367 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1039,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=416 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1040,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=417 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=7051,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=444 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1427,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=485 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1425,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=486 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1424,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=487 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1423,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=488 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1422,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=489 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1421,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=490 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1420,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=491 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1419,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=492 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1418,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=493 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1417,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=494 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1416,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=496 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1415,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=497 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1362,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=498 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1414,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=499 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1363,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=500 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1413,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=501 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1411,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=502 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1409,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=503 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1365,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=504 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1369,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=505 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1408,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=506 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1406,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=507 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1362,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=511 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1364,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=514 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1367,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=515 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1366,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=516 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1405,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=517 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1364,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=518 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1401,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=519 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1415,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=520 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1368,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=521 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1399,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=523 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1370,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=524 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1398,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=525 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1371,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=526 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1397,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=527 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1396,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=528 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1372,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=529 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1373,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=530 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1374,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=531 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1375,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=532 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1376,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=533 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1380,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=534 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1395,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=535 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1394,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=536 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1393,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=537 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1392,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=538 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1391,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=539 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1390,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=540 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1389,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=541 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1387,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=542 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1386,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=543 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1385,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=544 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1384,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=545 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1382,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=546 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1381,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=547 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1362,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=550 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1363,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=551 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1364,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=552 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1365,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=553 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1366,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=554 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1367,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=555 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1368,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=556 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1369,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=557 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1370,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=558 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1371,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=559 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1372,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=560 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1374,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=562 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1375,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=563 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1376,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=564 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1379,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=565 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1380,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=566 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1381,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=567 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1382,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=568 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1384,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=569 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1385,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=571 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1386,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=572 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1387,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=573 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1045,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=574 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1389,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=575 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1390,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=576 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1391,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=577 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1392,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=578 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1393,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=579 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1394,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=580 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1395,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=581 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1396,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=582 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1397,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=583 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1398,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=584 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1399,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=585 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1400,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=586 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1401,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=587 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1402,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=588 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1405,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=589 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1409,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=590 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1409,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=591 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1411,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=592 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1413,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=593 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1414,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=594 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1415,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=595 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1416,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=596 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1418,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=598 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1419,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=599 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1420,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=600 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1421,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=601 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1422,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=602 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1423,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=603 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1424,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=604 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1425,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=605 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1427,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=606 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1428,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=607 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1429,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=608 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1430,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=609 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1431,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=610 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1432,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=611 +visiome,https://visiome.neuroinf.jp/modules/xoonips/detail.php?item_id=7252,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=612 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1434,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=613 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1435,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=614 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1450,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=615 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1452,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=616 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1453,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=617 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1454,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=618 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1455,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=619 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1458,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=620 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1460,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=621 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1461,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=622 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1462,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=623 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1463,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=624 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1466,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=625 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1465,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=626 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1467,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=627 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1470,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=628 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1471,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=629 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1472,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=630 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1473,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=631 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1474,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=632 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1476,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=633 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1477,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=634 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1479,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=635 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1481,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=636 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1482,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=637 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1483,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=638 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1486,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=639 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1487,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=640 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1488,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=641 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1489,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=642 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1490,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=643 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1493,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=644 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1496,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=645 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1497,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=646 +cerebellum,https://cerebellum.neuroinf.jp/modules/xoonips/detail.php?item_id=1498,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=647 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/533/SundtEtAl2015.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=656 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/536/baker_etal_JCNS_2010.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=657 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/538/CS56PyModelDB.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=659 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/539/TCconvergenceModel.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=660 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/540/BahlEtAl2012.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=661 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/541/ACh_ModelDB.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=662 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/543/OLMmodel_r3.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=664 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/548/GentilettiEtAl2016.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=668 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/556/FUS_model.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=677 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/560/ShepherdBrayton1979.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=680 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/561/gc-1.1_r2.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=681 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/564/VladimirovTuTraub2012.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=683 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/565/xiaoshenli.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=684 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/566/kv72-R213QW-mutations_r2.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=685 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/567/Ih_current.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=686 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/569/Schizophr.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=687 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/570/SaudargieneEtAl2015.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=688 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/571/bpap.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=689 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/572/magical7.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=691 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/575/HyunEtAl2015.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=696 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/576/MasurkarChen2011_r1.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=697 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/577/Nakano_FICN_model_r1.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=698 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/582/AshhadNarayanan2013.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=699 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/583/DiFrancescoNoble1985.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=700 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/584/DGC.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=701 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/586/DG_BC.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=703 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/587/DRG_Devor.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=704 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/588/Kv72_ModelDB.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=705 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/589/SousaEtAl2014.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=706 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/590/MiglioreEtAl2015.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=707 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/592/Chloride_Model.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=708 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/593/MiglioreEJN2016_r2.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=709 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/595/Moore2015.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=711 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/597/FFI_CA1_r3.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=713 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/598/stadler2014_layerV_r1.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=714 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/600/2VN.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=716 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/602/Branch_Point_Tapering.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=718 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/604/MenonEtAl2009_r1.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=720 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/606/CA3Atrophy.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=722 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/607/Gorin_et_al_2016.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=723 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/608/Poleg-PolskyDiamond2011.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=724 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/613/Demo.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=728 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/614/ShortEtAl2016.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=729 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/618/Casaleggio2014.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=733 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/623/MiglioreMcTavish2013.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=736 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/624/KimEtAl2017.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=737 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/626/fig1b.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=738 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/627/cortex_r1.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=739 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/629/oltedal.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=741 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/632/ka_rgc.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=744 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/634/na_rgc.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=745 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/636/V1_PFC_ModelDB.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=747 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/640/moore83.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=751 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/642/SpaceClampDemo.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=753 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/644/anderson.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=755 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/645/VNO.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=756 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/645/VNO.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=757 +cns,https://cns.neuroinf.jp/modules/fmanager/index.php/view/647/Watanabe-et-al_2017_r1.zip,http://sim.neuroinf.jp/modules/xoonips/detail.php?item_id=758 diff --git a/package.json b/package.json index 2f245d3..5871a9a 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,41 @@ { "name": "dynamicbrain", - "version": "0.1.0", + "version": "1.0.0", "private": true, "dependencies": { - "@types/jest": "24.0.17", + "@types/async-lock": "^1.1.1", + "@types/jest": "24.0.18", + "@types/lokijs": "^1.5.2", "@types/node": "12.7.2", "@types/react": "16.9.2", - "@types/react-dom": "16.8.5", + "@types/react-dom": "16.9.0", + "@types/react-helmet": "^5.0.9", + "@types/react-html-parser": "^2.0.1", + "@types/react-overlays": "^1.1.3", + "@types/react-router-dom": "^4.3.5", + "@types/react-router-hash-link": "^1.2.1", + "@types/xregexp": "^3.0.30", + "async-lock": "^1.2.2", + "axios": "^0.19.0", + "lokijs": "^1.5.7", + "moment": "^2.24.0", + "rc-tree": "^3.0.0-alpha.15", "react": "^16.9.0", + "react-app-polyfill": "^1.0.2", + "react-cookie": "^4.0.1", "react-dom": "^16.9.0", + "react-ga": "^2.6.0", + "react-helmet": "^5.2.1", + "react-html-parser": "^2.0.2", + "react-image-lightbox": "^5.1.0", + "react-overlays": "^1.2.0", + "react-router-dom": "^5.0.1", + "react-router-hash-link": "^1.2.2", "react-scripts": "3.1.1", - "typescript": "3.5.3" + "react-spinner-material": "^1.1.3", + "react-twitter-widgets": "^1.7.1", + "typescript": "3.5.3", + "xregexp": "^4.2.4" }, "scripts": { "start": "react-scripts start", @@ -25,12 +50,17 @@ "production": [ ">0.2%", "not dead", - "not op_mini all" + "not op_mini all", + "ie 11" ], "development": [ "last 1 chrome version", "last 1 firefox version", - "last 1 safari version" + "last 1 safari version", + "ie 11" ] + }, + "devDependencies": { + "less": "^3.10.3" } } diff --git a/public/.htaccess b/public/.htaccess new file mode 100644 index 0000000..c0d9bbc --- /dev/null +++ b/public/.htaccess @@ -0,0 +1,8 @@ +RewriteEngine on +RewriteBase / + +RewriteCond %{QUERY_STRING} (^|&)file_id=([0-9]+)($|&) +RewriteRule ^modules/xoonips/download.php /database/file/%2? [R=301,L] + +RewriteCond %{REQUEST_FILENAME} !-f +RewriteRule . /index.html [L] diff --git a/public/favicon.ico b/public/favicon.ico index a11777c..59f19c8 100644 Binary files a/public/favicon.ico and b/public/favicon.ico differ diff --git a/public/index.html b/public/index.html index a146b6f..4496553 100644 --- a/public/index.html +++ b/public/index.html @@ -7,37 +7,17 @@ - - + + + + - - React App + Dynamic Brain Platform - Official Site
    - diff --git a/public/logo192.png b/public/logo192.png deleted file mode 100644 index fc44b0a..0000000 Binary files a/public/logo192.png and /dev/null differ diff --git a/public/logo512.png b/public/logo512.png deleted file mode 100644 index a4e47a6..0000000 Binary files a/public/logo512.png and /dev/null differ diff --git a/public/manifest.json b/public/manifest.json index d1c1d1d..b39b2a8 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,22 +1,12 @@ { - "short_name": "React App", - "name": "Create React App Sample", + "short_name": "Dynamic Brain Platform", + "name": "Dynamic Brain Platform", "icons": [ { "src": "favicon.ico", - "sizes": "64x64 32x32 24x24 16x16", + "sizes": "32x32 16x16", "type": "image/x-icon" - }, - { - "src": "logo192.png", - "type": "image/png", - "sizes": "192x192" - }, - { - "src": "logo512.png", - "type": "image/png", - "sizes": "512x512" - } + } ], "start_url": ".", "display": "standalone", diff --git a/src/App.css b/src/App.css index b41d297..1803609 100644 --- a/src/App.css +++ b/src/App.css @@ -1,33 +1,2 @@ -.App { - text-align: center; -} - -.App-logo { - animation: App-logo-spin infinite 20s linear; - height: 40vmin; - pointer-events: none; -} - -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} +@import url('./common/assets/xoops.css'); +@import url('./common/assets/theme/style.css'); \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index 226ee63..27c385e 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,26 +1,20 @@ -import React from 'react'; -import logo from './logo.svg'; +import React, { Component } from 'react'; +import { BrowserRouter } from 'react-router-dom'; +import { CookiesProvider } from 'react-cookie'; +import AppRoot from './common/AppRoot'; import './App.css'; -const App: React.FC = () => { - return ( -
    - ); +class App extends Component { + + render() { + return ( + + + + + + ); + } } export default App; diff --git a/src/common/AppRoot.tsx b/src/common/AppRoot.tsx new file mode 100644 index 0000000..fc38628 --- /dev/null +++ b/src/common/AppRoot.tsx @@ -0,0 +1,85 @@ +import React, { Component } from 'react'; +import { ReactCookieProps, withCookies } from 'react-cookie'; +import ReactGA from 'react-ga'; +import Helmet from 'react-helmet'; +import { RouteComponentProps, withRouter } from 'react-router-dom'; +import Config, { MultiLang } from '../config'; +import Functions from '../functions'; +import CenterColumn from './CenterColumn'; +import Header from './Header'; +import LeftColumn from './LeftColumn'; +import Footer from './Footer'; + + +interface Props extends RouteComponentProps, ReactCookieProps { } +interface State { + lang: MultiLang; +} + +class AppRoot extends Component { + + constructor(props: Props) { + super(props); + this.state = { lang: 'en' }; + if (process.env.NODE_ENV === 'production' && Config.GOOGLE_ANALYTICS_TRACKING_ID !== '') { + ReactGA.initialize(Config.GOOGLE_ANALYTICS_TRACKING_ID); + } + } + + static getDerivedStateFromProps(nextProps: Props, prevState: State) { + const params = new URLSearchParams(nextProps.location.search); + const param_lang = params.get('ml_lang'); + const cookie_lang = typeof nextProps.cookies !== 'undefined' ? nextProps.cookies.get('ml_lang') : null; + let lang = param_lang || (typeof cookie_lang === 'string' ? cookie_lang : null) || prevState.lang; + if (lang !== 'en' && lang !== 'ja') { + lang = 'en'; + } + if (cookie_lang !== lang) { + if (typeof nextProps.cookies !== 'undefined') { + nextProps.cookies.set('ml_lang', lang, { path: '/' }); + } + } + if (prevState.lang !== lang) { + return { lang }; + } + return null; + } + + componentDidMount() { + const { pathname } = this.props.location; + if (process.env.NODE_ENV === 'production' && Config.GOOGLE_ANALYTICS_TRACKING_ID !== '') { + ReactGA.set({ page: pathname }); + ReactGA.pageview(pathname); + } + } + + componentDidUpdate(prevProps: Props) { + const { pathname, search } = this.props.location; + if (process.env.NODE_ENV === 'production' && Config.GOOGLE_ANALYTICS_TRACKING_ID !== '') { + ReactGA.set({ page: pathname }); + ReactGA.pageview(pathname); + } + if (pathname !== prevProps.location.pathname || search !== prevProps.location.search) { + window.scrollTo(0, 0); + } + } + + render() { + const { lang } = this.state; + return ( +
    + + {Functions.siteTitle(lang)} - {Functions.siteSlogan(lang)} + +
    +
    + + +
    +
    +
    + ); + } +} + +export default withCookies(withRouter(AppRoot)); diff --git a/src/common/CenterColumn.tsx b/src/common/CenterColumn.tsx new file mode 100644 index 0000000..243c8a7 --- /dev/null +++ b/src/common/CenterColumn.tsx @@ -0,0 +1,65 @@ +import React from 'react'; +import { Route, Switch } from 'react-router-dom'; +import { MultiLang } from '../config'; +import Welcome from '../custom/blocks/Welcome'; +import Rankings from '../database/blocks/Rankings'; +import RecentContents from '../database/blocks/RecentContents'; +import Functions from '../functions'; +import MainContent from './MainContent'; + +interface Props { + lang: MultiLang; +} + +const CenterBlocks = (props: Props) => { + const { lang } = props; + return ( + <> +
    +
    +
    + +
    +
    +
    +
    +
    +
    +
    {Functions.mlang('[en]XooNIps Rankings[/en][ja]XooNIps ランキング[/ja]', lang)}
    +
    + +
    +
    +
    +
    +
    +
    {Functions.mlang('[en]XooNIps Update[/en][ja]XooNIps アップデート[/ja]', lang)}
    +
    + +
    +
    + +
    +
    + + ); +} + +const CenterColumn = (props: Props) => { + const { lang } = props; + + return ( +
    + + } /> + +
    + +
    + } /> +
    +
    + ); +} + +export default CenterColumn; \ No newline at end of file diff --git a/src/common/Footer.tsx b/src/common/Footer.tsx new file mode 100644 index 0000000..45dc700 --- /dev/null +++ b/src/common/Footer.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import { MultiLang } from '../config'; +import LinkImage from './lib/LinkImage'; +import Functions from '../functions'; +import bannerPhysiome from './assets/theme/images/banner_physiome.png'; +import bannerCBS from './assets/theme/images/banner_riken-cbs.png'; +import bannerRIKEN from './assets/theme/images/banner_riken.png'; +import bannerXooNIps from './assets/theme/images/banner_xoonips.png'; + +interface Props { + lang: MultiLang; +} + +const Footer = (props: Props) => { + const { lang } = props; + return ( +
    +
    +
    Copyright (C) 2018 Neuroinformatics Unit, RIKEN Center for Brain Science
    +
    + + + + +
    +
    +
    + ); +} + +export default Footer; diff --git a/src/common/Header.tsx b/src/common/Header.tsx new file mode 100644 index 0000000..81cbb46 --- /dev/null +++ b/src/common/Header.tsx @@ -0,0 +1,58 @@ +import React, { ChangeEvent, Component, MouseEvent } from 'react'; +import { RouteComponentProps, withRouter, Link } from 'react-router-dom'; +import imageJapanNode from '../common/assets/theme/images/icon_jnode.png'; +import Config, { MultiLang } from '../config'; +import ItemUtil from '../database/lib/ItemUtil'; +import Functions from '../functions'; +import LinkImage from './lib/LinkImage'; + +interface Props extends RouteComponentProps { + lang: MultiLang; +} + +interface State { + keyword: string; +} + +class Header extends Component { + + constructor(props: Props) { + super(props); + this.handleChangeKeyword = this.handleChangeKeyword.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); + this.state = { keyword: '' }; + } + + handleChangeKeyword(event: ChangeEvent) { + const keyword = event.target.value; + this.setState({ keyword }); + } + + handleSubmit(event: MouseEvent) { + event.preventDefault(); + const keyword = this.state.keyword.trim(); + if (keyword !== '') { + const url = ItemUtil.getSearchByKeywordUrl('all', this.state.keyword); + this.props.history.push(url); + } + } + + render() { + const { lang } = this.props; + const title = Functions.mlang(Config.SITE_TITLE, lang); + return ( + + ); + } +} + +export default withRouter(Header); \ No newline at end of file diff --git a/src/common/LeftColumn.tsx b/src/common/LeftColumn.tsx new file mode 100644 index 0000000..dbeb18b --- /dev/null +++ b/src/common/LeftColumn.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { Route, Switch } from 'react-router'; +import { Timeline } from 'react-twitter-widgets'; +import { MultiLang } from '../config'; +import CreditsMenu from '../credits/block/CreditsMenu'; +import IndexTree from '../database/blocks/IndexTree'; +import Functions from '../functions'; +import MainMenu from './blocks/MainMenu'; +import SelectLang from './blocks/SelectLang'; + +interface Props { + lang: MultiLang; +} + +const LeftColumn = (props: Props) => { + const { lang } = props; + return ( +
    +
    +
    + +
    +
    +
    +
    {Functions.mlang('[en]Menu[/en][ja]メニュー[/ja]', lang)}
    +
    + +
    +
    +
    +
    {Functions.mlang('[en]Site Information[/en][ja]ウェブサイト情報[/ja]', lang)}
    +
    + +
    +
    + + +
    +
    Twitter
    +
    + +
    +
    + } /> + +
    +
    {Functions.mlang('[en]Index Tree[/en][ja]インデックスツリー[/ja]', lang)}
    +
    + +
    +
    + } /> +
    +
    + ); +} + +export default LeftColumn; diff --git a/src/common/MainContent.tsx b/src/common/MainContent.tsx new file mode 100644 index 0000000..5b3d2ea --- /dev/null +++ b/src/common/MainContent.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { Redirect, Route, RouteComponentProps, Switch } from 'react-router-dom'; +import Config, { MultiLang } from '../config'; +import Credits from '../credits/Credits'; +import CreditsXoopsPathRedirect from '../credits/CreditsXoopsPathRedirect'; +import Database from '../database/Database'; +import DatabaseXoopsPathRedirect from '../database/DatabaseXoopsPathRedirect'; +import MediaWiki from '../mediawiki/MediaWiki'; +import MediaWikiXoopsPathRedirect from '../mediawiki/MediaWikiXoopsPathRedirect'; +import Pico from '../pico/Pico'; +import XoopsPathRedirect from './XoopsPathRedirect'; + +interface Props { + lang: MultiLang; +} + +const MainContent = (props: Props) => { + const { lang } = props; + return ( +
    + + } /> + } /> + {Config.PICO_MODULES.map((name) => + } /> + )} + { + const name = lang === 'en' ? 'Main_Page' : 'メインページ'; + return ; + }} /> + ) => { + const { match } = props; + const { params } = match; + const name = params.name; + return ; + }} /> + } /> + } /> + {Config.PICO_MODULES.map((name) => + } /> + )} + } /> + + + +
    + ); +} + +export default MainContent; diff --git a/src/common/XoopsPathRedirect.tsx b/src/common/XoopsPathRedirect.tsx new file mode 100644 index 0000000..aaf8a18 --- /dev/null +++ b/src/common/XoopsPathRedirect.tsx @@ -0,0 +1,40 @@ +import React, { Component } from 'react'; +import { Redirect, RouteComponentProps } from 'react-router'; +import { MultiLang } from '../config'; +import PageNotFound from './lib/PageNotFound'; + +interface Params { + module: string; + pathname: string; +} + +interface Props extends RouteComponentProps { + lang: MultiLang; +} + +class XoopsPathRedirect extends Component { + + getRedirectUrl() { + const { pathname } = this.props.location; + switch (pathname || '') { + case '/index.php': { + return '/'; + } + } + return ''; + } + + render() { + const { lang } = this.props; + if (this.props.location.pathname === '/') { + return null; + } + const url = this.getRedirectUrl(); + if (url === '') { + return ; + } + return ; + } +} + +export default XoopsPathRedirect; diff --git a/src/common/assets/images/mlang_english.gif b/src/common/assets/images/mlang_english.gif new file mode 100644 index 0000000..4ff614e Binary files /dev/null and b/src/common/assets/images/mlang_english.gif differ diff --git a/src/common/assets/images/mlang_japanese.gif b/src/common/assets/images/mlang_japanese.gif new file mode 100644 index 0000000..5768206 Binary files /dev/null and b/src/common/assets/images/mlang_japanese.gif differ diff --git a/src/common/assets/images/no_avatar.gif b/src/common/assets/images/no_avatar.gif new file mode 100644 index 0000000..62fff0f Binary files /dev/null and b/src/common/assets/images/no_avatar.gif differ diff --git a/src/common/assets/images/pagact.gif b/src/common/assets/images/pagact.gif new file mode 100644 index 0000000..3f5b855 Binary files /dev/null and b/src/common/assets/images/pagact.gif differ diff --git a/src/common/assets/images/paginact.gif b/src/common/assets/images/paginact.gif new file mode 100644 index 0000000..7a2bc62 Binary files /dev/null and b/src/common/assets/images/paginact.gif differ diff --git a/src/common/assets/images/pagneutral.gif b/src/common/assets/images/pagneutral.gif new file mode 100644 index 0000000..b731713 Binary files /dev/null and b/src/common/assets/images/pagneutral.gif differ diff --git a/src/common/assets/images/rank3dbf8e94a6f72.gif b/src/common/assets/images/rank3dbf8e94a6f72.gif new file mode 100644 index 0000000..1c7c979 Binary files /dev/null and b/src/common/assets/images/rank3dbf8e94a6f72.gif differ diff --git a/src/common/assets/images/rank3dbf8e9e7d88d.gif b/src/common/assets/images/rank3dbf8e9e7d88d.gif new file mode 100644 index 0000000..a545faf Binary files /dev/null and b/src/common/assets/images/rank3dbf8e9e7d88d.gif differ diff --git a/src/common/assets/images/rank3dbf8ea81e642.gif b/src/common/assets/images/rank3dbf8ea81e642.gif new file mode 100644 index 0000000..50f3de7 Binary files /dev/null and b/src/common/assets/images/rank3dbf8ea81e642.gif differ diff --git a/src/common/assets/images/rank3dbf8eb1a72e7.gif b/src/common/assets/images/rank3dbf8eb1a72e7.gif new file mode 100644 index 0000000..64d8f29 Binary files /dev/null and b/src/common/assets/images/rank3dbf8eb1a72e7.gif differ diff --git a/src/common/assets/images/rank3dbf8edf15093.gif b/src/common/assets/images/rank3dbf8edf15093.gif new file mode 100644 index 0000000..704398e Binary files /dev/null and b/src/common/assets/images/rank3dbf8edf15093.gif differ diff --git a/src/common/assets/images/rank3dbf8ee8681cd.gif b/src/common/assets/images/rank3dbf8ee8681cd.gif new file mode 100644 index 0000000..95428a8 Binary files /dev/null and b/src/common/assets/images/rank3dbf8ee8681cd.gif differ diff --git a/src/common/assets/images/rank3e632f95e81ca.gif b/src/common/assets/images/rank3e632f95e81ca.gif new file mode 100644 index 0000000..224fbaa Binary files /dev/null and b/src/common/assets/images/rank3e632f95e81ca.gif differ diff --git a/src/common/assets/images/smil3dbd4bf386b36.gif b/src/common/assets/images/smil3dbd4bf386b36.gif new file mode 100644 index 0000000..51e517a Binary files /dev/null and b/src/common/assets/images/smil3dbd4bf386b36.gif differ diff --git a/src/common/assets/images/smil3dbd4d4e4c4f2.gif b/src/common/assets/images/smil3dbd4d4e4c4f2.gif new file mode 100644 index 0000000..ee53c7d Binary files /dev/null and b/src/common/assets/images/smil3dbd4d4e4c4f2.gif differ diff --git a/src/common/assets/images/smil3dbd4d6422f04.gif b/src/common/assets/images/smil3dbd4d6422f04.gif new file mode 100644 index 0000000..9a75a92 Binary files /dev/null and b/src/common/assets/images/smil3dbd4d6422f04.gif differ diff --git a/src/common/assets/images/smil3dbd4d75edb5e.gif b/src/common/assets/images/smil3dbd4d75edb5e.gif new file mode 100644 index 0000000..b1baee2 Binary files /dev/null and b/src/common/assets/images/smil3dbd4d75edb5e.gif differ diff --git a/src/common/assets/images/smil3dbd4d8676346.gif b/src/common/assets/images/smil3dbd4d8676346.gif new file mode 100644 index 0000000..5777f68 Binary files /dev/null and b/src/common/assets/images/smil3dbd4d8676346.gif differ diff --git a/src/common/assets/images/smil3dbd4d99c6eaa.gif b/src/common/assets/images/smil3dbd4d99c6eaa.gif new file mode 100644 index 0000000..87a792e Binary files /dev/null and b/src/common/assets/images/smil3dbd4d99c6eaa.gif differ diff --git a/src/common/assets/images/smil3dbd4daabd491.gif b/src/common/assets/images/smil3dbd4daabd491.gif new file mode 100644 index 0000000..95a63f2 Binary files /dev/null and b/src/common/assets/images/smil3dbd4daabd491.gif differ diff --git a/src/common/assets/images/smil3dbd4dbc14f3f.gif b/src/common/assets/images/smil3dbd4dbc14f3f.gif new file mode 100644 index 0000000..77c71c0 Binary files /dev/null and b/src/common/assets/images/smil3dbd4dbc14f3f.gif differ diff --git a/src/common/assets/images/smil3dbd4dcd7b9f4.gif b/src/common/assets/images/smil3dbd4dcd7b9f4.gif new file mode 100644 index 0000000..2e4dfa5 Binary files /dev/null and b/src/common/assets/images/smil3dbd4dcd7b9f4.gif differ diff --git a/src/common/assets/images/smil3dbd4ddd6835f.gif b/src/common/assets/images/smil3dbd4ddd6835f.gif new file mode 100644 index 0000000..01b5a60 Binary files /dev/null and b/src/common/assets/images/smil3dbd4ddd6835f.gif differ diff --git a/src/common/assets/images/smil3dbd4df1944ee.gif b/src/common/assets/images/smil3dbd4df1944ee.gif new file mode 100644 index 0000000..49697c5 Binary files /dev/null and b/src/common/assets/images/smil3dbd4df1944ee.gif differ diff --git a/src/common/assets/images/smil3dbd4e02c5440.gif b/src/common/assets/images/smil3dbd4e02c5440.gif new file mode 100644 index 0000000..004261b Binary files /dev/null and b/src/common/assets/images/smil3dbd4e02c5440.gif differ diff --git a/src/common/assets/images/smil3dbd4e1748cc9.gif b/src/common/assets/images/smil3dbd4e1748cc9.gif new file mode 100644 index 0000000..50f9984 Binary files /dev/null and b/src/common/assets/images/smil3dbd4e1748cc9.gif differ diff --git a/src/common/assets/images/smil3dbd4e29bbcc7.gif b/src/common/assets/images/smil3dbd4e29bbcc7.gif new file mode 100644 index 0000000..4a96ea1 Binary files /dev/null and b/src/common/assets/images/smil3dbd4e29bbcc7.gif differ diff --git a/src/common/assets/images/smil3dbd4e398ff7b.gif b/src/common/assets/images/smil3dbd4e398ff7b.gif new file mode 100644 index 0000000..15402e7 Binary files /dev/null and b/src/common/assets/images/smil3dbd4e398ff7b.gif differ diff --git a/src/common/assets/images/smil3dbd4e4c2e742.gif b/src/common/assets/images/smil3dbd4e4c2e742.gif new file mode 100644 index 0000000..99368ba Binary files /dev/null and b/src/common/assets/images/smil3dbd4e4c2e742.gif differ diff --git a/src/common/assets/images/smil3dbd4e5e7563a.gif b/src/common/assets/images/smil3dbd4e5e7563a.gif new file mode 100644 index 0000000..172ecf8 Binary files /dev/null and b/src/common/assets/images/smil3dbd4e5e7563a.gif differ diff --git a/src/common/assets/images/smil3dbd4e7853679.gif b/src/common/assets/images/smil3dbd4e7853679.gif new file mode 100644 index 0000000..a66421e Binary files /dev/null and b/src/common/assets/images/smil3dbd4e7853679.gif differ diff --git a/src/common/assets/main-menu.json b/src/common/assets/main-menu.json new file mode 100644 index 0000000..d9bb3fe --- /dev/null +++ b/src/common/assets/main-menu.json @@ -0,0 +1,38 @@ +[ + { + "title": "[en]Home[/en][ja]ホーム[/ja]", + "link": "/" + }, + { + "title": "[en]About \"Dynamic Brain\"[/en][ja]\"Dynamic Brain\"とは[/ja]", + "link": "/documents/index.php?content_id=14" + }, + { + "title": "[en]Articles[/en][ja]特集記事[/ja]", + "link": "/mediawiki/" + }, + { + "title": "[en]Academic Conferences[/en][ja]学術会議[/ja]", + "link": "/mediawiki/Academic_conferences" + }, + { + "title": "[en]Collaborative Projects[/en][ja]連携プロジェクト[/ja]", + "link": "/mediawiki/Collaborative_Projects" + }, + { + "title": "[en]Collaborative Hackathon[/en][ja]連携ハッカソン[/ja]", + "link": "/mediawiki/Hackathon_Page" + }, + { + "title": "[en]Models[/en][ja]数理モデル[/ja]", + "link": "/database/search/itemtype/model" + }, + { + "title": "[en]How to get \"PhysioDesigner\"[/en][ja]PhysioDesignerダウンロード[/ja]", + "link": "http://physiodesigner.org/download/" + }, + { + "title": "[en]See more...[/en][ja]更に見る...[/ja]", + "link": "/database" + } +] diff --git a/src/common/assets/theme/images/arrow.png b/src/common/assets/theme/images/arrow.png new file mode 100644 index 0000000..43f6c3e Binary files /dev/null and b/src/common/assets/theme/images/arrow.png differ diff --git a/src/common/assets/theme/images/banner_physiome.png b/src/common/assets/theme/images/banner_physiome.png new file mode 100644 index 0000000..c53915a Binary files /dev/null and b/src/common/assets/theme/images/banner_physiome.png differ diff --git a/src/common/assets/theme/images/banner_riken-cbs.png b/src/common/assets/theme/images/banner_riken-cbs.png new file mode 100644 index 0000000..f7a5633 Binary files /dev/null and b/src/common/assets/theme/images/banner_riken-cbs.png differ diff --git a/src/common/assets/theme/images/banner_riken.png b/src/common/assets/theme/images/banner_riken.png new file mode 100644 index 0000000..d690405 Binary files /dev/null and b/src/common/assets/theme/images/banner_riken.png differ diff --git a/src/common/assets/theme/images/banner_xoonips.png b/src/common/assets/theme/images/banner_xoonips.png new file mode 100644 index 0000000..6fa26de Binary files /dev/null and b/src/common/assets/theme/images/banner_xoonips.png differ diff --git a/src/common/assets/theme/images/bg.png b/src/common/assets/theme/images/bg.png new file mode 100644 index 0000000..2d8f9e2 Binary files /dev/null and b/src/common/assets/theme/images/bg.png differ diff --git a/src/common/assets/theme/images/brain-bike.png b/src/common/assets/theme/images/brain-bike.png new file mode 100644 index 0000000..de9c420 Binary files /dev/null and b/src/common/assets/theme/images/brain-bike.png differ diff --git a/src/common/assets/theme/images/i.png b/src/common/assets/theme/images/i.png new file mode 100644 index 0000000..9dca56f Binary files /dev/null and b/src/common/assets/theme/images/i.png differ diff --git a/src/common/assets/theme/images/icon_jnode.png b/src/common/assets/theme/images/icon_jnode.png new file mode 100644 index 0000000..a0046e5 Binary files /dev/null and b/src/common/assets/theme/images/icon_jnode.png differ diff --git a/src/common/assets/theme/images/indent.png b/src/common/assets/theme/images/indent.png new file mode 100644 index 0000000..c1bf4a4 Binary files /dev/null and b/src/common/assets/theme/images/indent.png differ diff --git a/src/common/assets/theme/images/indent_hover.png b/src/common/assets/theme/images/indent_hover.png new file mode 100644 index 0000000..bc34695 Binary files /dev/null and b/src/common/assets/theme/images/indent_hover.png differ diff --git a/src/common/assets/theme/images/logo.png b/src/common/assets/theme/images/logo.png new file mode 100644 index 0000000..95e791c Binary files /dev/null and b/src/common/assets/theme/images/logo.png differ diff --git a/src/common/assets/theme/images/plate.png b/src/common/assets/theme/images/plate.png new file mode 100644 index 0000000..bd9816c Binary files /dev/null and b/src/common/assets/theme/images/plate.png differ diff --git a/src/common/assets/theme/images/plateB.gif b/src/common/assets/theme/images/plateB.gif new file mode 100644 index 0000000..5afa875 Binary files /dev/null and b/src/common/assets/theme/images/plateB.gif differ diff --git a/src/common/assets/theme/images/plate_bottom.png b/src/common/assets/theme/images/plate_bottom.png new file mode 100644 index 0000000..5e08be3 Binary files /dev/null and b/src/common/assets/theme/images/plate_bottom.png differ diff --git a/src/common/assets/theme/images/plate_top.png b/src/common/assets/theme/images/plate_top.png new file mode 100644 index 0000000..3c3296c Binary files /dev/null and b/src/common/assets/theme/images/plate_top.png differ diff --git a/src/common/assets/theme/style.css b/src/common/assets/theme/style.css new file mode 100644 index 0000000..565a233 --- /dev/null +++ b/src/common/assets/theme/style.css @@ -0,0 +1,312 @@ +*, +*::before, +*::after { + box-sizing: border-box; +} + +body { + font-family: arial, sans-serif; + color: #333; + min-width: 850px; + background: #003 url(images/bg.png) repeat-y scroll left top; + margin: 0; + font-size: 95%; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin-bottom: 0.5rem; + font-family: inherit; + font-weight: 500; + line-height: 1.2; + color: inherit; +} +h1 { + font-size: 1.802em; +} +h2 { + font-size: 1.602em; +} +h3 { + font-size: 1.424em; +} +h4 { + font-size: 1.266em; +} +h5 { + font-size: 1.125em; +} +h6 { + font-size: 1em; +} + +a { + color: #f66; + text-decoration: none; +} +a:hover { + color: #36f; + text-decoration: none; +} + +table { + width: 100%; +} + +tr, +td, +th { + text-align: left; +} + +.clearfix::after { + content: ""; + display: block; + clear: both; +} + +.hidden { + display: none; +} + +.text-center { + text-align: center; +} +.text-left { + text-align: left; +} +.text-right { + text-align: right; +} + +.font-weight-bold { + font-weight: bold; +} +.font-italic { + font-style: italic; +} + +.even, +.odd { + padding: 2px; + border-bottom: 2px groove #fff; + font-size: 95%; +} + +.plate { + background-image: url(images/plate.png); + border-left: 3px solid #999; + border-right: 3px solid #999; + color: #000; +} +.plate::before { + content: ""; + display: block; + height: 15px; + background: url(images/plate_top.png) repeat-x left top; +} +.plate::after { + content: ""; + display: block; + height: 15px; + background: url(images/plate_bottom.png) repeat-x left bottom; +} +.plate a { + color: #036; +} +.plate a:hover { + color: #36f; +} +.plate h4 { + color: #369; + font-weight: bold; + border-bottom: 2px groove #fff; +} +.block .blockTitle { + height: 21px; + margin-bottom: 0.4rem; + padding: 0 10px 0 32px; + background: url(images/arrow.png) no-repeat 7px top; + color: #369; + line-height: 21px; + font-weight: bold; +} +.block .blockContent { + padding: 0 10px; + font-size: 13px; +} + +.plate td { + padding: 0; + vertical-align: top; + font-family: Verdana, Arial, Helvetica, sans-serif, serif; + line-height: 150%; +} + +.plate th { + padding: 4px; + border-bottom: 2px groove #fff; + vertical-align: middle; + color: #66c; +} + +.plate .head { + padding: 5px; + font-weight: bold; + border-bottom: 2px groove #fff; + font-size: 95%; +} + +#header .left { + float: left; +} +#header .logo { + background-image: url(images/logo.png); + height: 100px; + width: 400px; +} +#header .logo a { + display: block; + width: 100%; + height: 100%; +} +#header .right { + margin: 5px 15px; + text-align: right; +} +#header .searchInput { + margin: 0 5px; + width: 180px; + background-color: #336; + color: #ccc; +} +#header .searchButton { + margin: 0 15px 0 0; + border-top: 2px groove #999; + border-left: 2px groove #999; + border-right: 2px ridge #fff; + border-bottom: 2px ridge #fff; + background-color: #336; + color: #ccc; + font-size: 14px; +} + +#footer { + text-align: right; + margin-top: 30px; +} +#footer .plate { + border: none; +} +#footer .plate::before { + height: 20px; +} +#footer .plate::after { + height: 5px; + background: none; +} +#footer .copyright { + color: #366; + font-size: 80%; + margin-right: 10px; +} +#footer .links { + margin-right: 10px; +} +#footer .links img { + margin: 10px 3px; +} +#main { + margin: 0px 5px; + line-height: 1.5; +} + +.leftcolumn { + float: left; + width: 230px; +} +.leftcolumn .block { + margin: 10px 5px 10px 10px; +} +.centercolumn { + float: right; + width: calc(100% - 230px); +} +.centercolumn > .block, +.centercolumn > .plate { + margin: 10px 10px 10px 5px; +} +.centerCcolumn > .block { + margin: 10px 10px 10px 15px; +} +.centerLcolumn { + float: left; + width: 50%; +} +.centerLcolumn .block, +.centerRcolumn .block { + margin: 10px; +} +.centerRcolumn { + float: right; + width: 50%; +} +.mainContent { + margin: 0 20px; +} +.mainContent table.listTable { + border-collapse: collapse !important; +} +.mainContent table td { + vertical-align: top; +} + +ul.mainmenu { + list-style-type: none; + margin: 0; + padding: 0; +} +.mainmenu a, +.mainmenu a.menuTop, +.mainmenu a.menuMain, +.mainmenu a.menuSub { + display: block; + text-indent: 15px; + color: #333; + background: url(images/indent.png) no-repeat left 2px; +} +.mainmenu a:hover { + color: #f00; + background: url(images/indent_hover.png) no-repeat left 2px; +} + +.welcome { + color: #ccc; + margin-bottom: 30px; + font-size: 14px; + min-height: 420px; + background: url(images/brain-bike.png) no-repeat right bottom; +} +.welcome h3 { + margin-top: 1.5em; +} +.welcome .articles { + padding-left: 30px; +} +.welcome .articles .article .title { + display: inline-block; + max-width: calc(100% - 400px); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.welcome .announce { + max-width: calc(100% - 200px); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} diff --git a/src/common/assets/xoops.css b/src/common/assets/xoops.css new file mode 100644 index 0000000..88f768a --- /dev/null +++ b/src/common/assets/xoops.css @@ -0,0 +1,17 @@ +img {border: 0;} + +#xoopsHiddenText {visibility: hidden; color: #000000; font-weight: normal; font-style: normal; text-decoration: none;} + +.pagneutral {font-size: 10px; width: 16px; height: 19px;text-align: center; background-image: url(./images/pagneutral.gif);} +.pagact {font-size: 10px; width: 16px; height: 19px;text-align: center; background-image: url(./images/pagact.gif);} +.paginact {font-size: 10px; width: 16px; height: 19px;text-align: center; background-image: url(./images/paginact.gif);} + + +#mainmenu a {text-align:left; display: block; margin: 0; padding: 4px;} +#mainmenu a.menuTop {padding-left: 3px;} +#mainmenu a.menuMain {padding-left: 3px;} +#mainmenu a.menuSub {padding-left: 9px;} + +#usermenu a {text-align:left; display: block; margin: 0; padding: 4px;} +#usermenu a.menuTop {} +#usermenu a.highlight {color: #0000ff; background-color: #fcc;} diff --git a/src/common/blocks/MainMenu.tsx b/src/common/blocks/MainMenu.tsx new file mode 100644 index 0000000..beb7251 --- /dev/null +++ b/src/common/blocks/MainMenu.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { MultiLang } from '../../config.js'; +import Functions from '../../functions'; +import mainMenus from '../assets/main-menu.json'; + +interface Props { + lang: MultiLang; +} + +const MainMenu = (props: Props) => { + const { lang } = props; + const links = mainMenus.map((item, idx) => { + const title = Functions.mlang(item.title, lang); + const style = idx === 0 ? "menuTop" : "menuMain"; + const link = item.link.match(/^https?:\/\//) ? + {title} : + {title}; + return
  • {link}
  • + }); + return ( +
      + {links} +
    + ); +} + +export default MainMenu; diff --git a/src/common/blocks/SelectLang.tsx b/src/common/blocks/SelectLang.tsx new file mode 100644 index 0000000..7c1480b --- /dev/null +++ b/src/common/blocks/SelectLang.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { RouteComponentProps, withRouter } from 'react-router'; +import { MultiLang } from '../../config'; + +interface Props extends RouteComponentProps { + lang: MultiLang; +} + +const SelectLang = (props: Props) => { + const { lang, history } = props; + const langs: MultiLang[] = ['en', 'ja']; + const titles = { + en: 'English', + ja: 'Japanese', + }; + return ( +
    + + +
    + ); +} + +export default withRouter(SelectLang); \ No newline at end of file diff --git a/src/common/lib/LangFlag.tsx b/src/common/lib/LangFlag.tsx new file mode 100644 index 0000000..191fb21 --- /dev/null +++ b/src/common/lib/LangFlag.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { RouteComponentProps, withRouter } from 'react-router'; +import { Link } from 'react-router-dom'; +import { MultiLang } from '../../config'; +import mlangEnglish from '../assets/images/mlang_english.gif'; +import mlangJapanese from '../assets/images/mlang_japanese.gif'; + +interface Props extends RouteComponentProps { + lang: MultiLang; +} + +const styleLink = { + fontSize: '8px', +}; +const styleImage = { + verticalAlign: 'middle', + border: '1px solid #000', +}; +const langResources = { + en: { image: mlangEnglish, title: 'English' }, + ja: { image: mlangJapanese, title: 'Japanese' }, +}; + +const LangFlag = (props: Props) => { + const { lang } = props; + const params = new URLSearchParams(props.location.search); + const flagLang = lang === 'en' ? 'ja' : 'en'; + params.set('ml_lang', flagLang); + const url = props.location.pathname + '?' + params.toString(); + return ( + + {langResources[flagLang].title} + + ); +} + + +export default withRouter(LangFlag); diff --git a/src/common/lib/LinkImage.tsx b/src/common/lib/LinkImage.tsx new file mode 100644 index 0000000..251e2cb --- /dev/null +++ b/src/common/lib/LinkImage.tsx @@ -0,0 +1,58 @@ +import React, { Component } from 'react'; +import { Link } from 'react-router-dom'; + +interface Props { + url: string; + title: string; + image: string; + imageHover?: string; +} + +interface State { + image: string; +} + +class LinkImage extends Component { + + constructor(props: Props) { + super(props); + this.state = { + image: props.image, + }; + this.handleMouseOver = this.handleMouseOver.bind(this); + this.handleMouseOut = this.handleMouseOut.bind(this); + } + + handleMouseOver() { + const { imageHover } = this.props; + if (typeof imageHover !== 'undefined') { + this.setState({ image: imageHover }) + } + } + + handleMouseOut() { + const { image: imageNormal, imageHover } = this.props; + if (typeof imageHover !== 'undefined') { + this.setState({ image: imageNormal }) + } + } + + render() { + const { url, title } = this.props; + const image = {title}; + if (url.match(/^(\/|\.)/) === null) { + return ( + + {image} + + ); + } + return ( + + {image} + + ); + } +} + +export default LinkImage; diff --git a/src/common/lib/Loading.tsx b/src/common/lib/Loading.tsx new file mode 100644 index 0000000..7eb83da --- /dev/null +++ b/src/common/lib/Loading.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import Spinner from 'react-spinner-material'; + +const Loading = () => { + return ( +
    + +
    + ); +} + +export default Loading; \ No newline at end of file diff --git a/src/common/lib/NoticeSiteHasBeenArchived.tsx b/src/common/lib/NoticeSiteHasBeenArchived.tsx new file mode 100644 index 0000000..c44a297 --- /dev/null +++ b/src/common/lib/NoticeSiteHasBeenArchived.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { MultiLang } from '../../config'; +import Functions from '../../functions'; + +interface Props { + lang: MultiLang; +} + +const NoticeSiteHasBeenArchived = (props: Props) => { + const { lang } = props; + const notice = '[en]This site has been archived since FY2019 and is no longer updated.[/en][ja]このサイトは、2019年度よりアーカイブサイトとして運用されています。[/ja]'; + return

    {Functions.mlang(notice, lang)}

    ; +} + +export default NoticeSiteHasBeenArchived; \ No newline at end of file diff --git a/src/common/lib/PageNotFound.tsx b/src/common/lib/PageNotFound.tsx new file mode 100644 index 0000000..e67d1cc --- /dev/null +++ b/src/common/lib/PageNotFound.tsx @@ -0,0 +1,52 @@ +import React, { Component } from 'react'; +import Helmet from 'react-helmet'; +import { RouteComponentProps, withRouter } from 'react-router'; +import { MultiLang } from '../../config'; +import Functions from '../../functions'; + +interface Props extends RouteComponentProps { + lang: MultiLang; +} + +class PageNotFound extends Component { + + private url = '/'; + private timer: NodeJS.Timer | null = null; + + goToTopPage() { + if (this.props.location.pathname !== '/') { + if (this.timer) { + clearTimeout(this.timer); + } + this.timer = setTimeout(() => { + this.timer = null; + this.props.history.push(this.url); + }, 5000); + } + } + + componentWillUnmount() { + if (this.timer) { + clearTimeout(this.timer); + } + } + + render() { + const { lang } = this.props; + this.goToTopPage(); + return ( +
    + + Page Not Found - {Functions.siteTitle(lang)} + +

    Page Not Found

    +
    +

    The page you were trying to access doesn't exist.

    +

    If the page does not automatically reload, please click here

    +
    +
    + ); + } +} + +export default withRouter(PageNotFound); \ No newline at end of file diff --git a/src/common/lib/UserRankStarImage.tsx b/src/common/lib/UserRankStarImage.tsx new file mode 100644 index 0000000..dd5f9e7 --- /dev/null +++ b/src/common/lib/UserRankStarImage.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { MultiLang } from '../../config'; +import Functions from '../../functions'; +import imageRank2 from '../assets/images/rank3dbf8e94a6f72.gif'; +import imageRank3 from '../assets/images/rank3dbf8e9e7d88d.gif'; +import imageRank4 from '../assets/images/rank3dbf8ea81e642.gif'; +import imageRank5 from '../assets/images/rank3dbf8eb1a72e7.gif'; +import imageRank6 from '../assets/images/rank3dbf8edf15093.gif'; +import imageRank7 from '../assets/images/rank3dbf8ee8681cd.gif'; +import imageRank1 from '../assets/images/rank3e632f95e81ca.gif'; + +interface Props { + lang: MultiLang; + rank: number; + posts: number; +} + +const userRanks = [ + { title: '[en]Just popping in[/en][ja]新米[/ja]', min: 0, max: 20, special: false, image: imageRank1 }, + { title: '[en]Not too shy to talk[/en][ja]半人前[/ja]', min: 21, max: 40, special: false, image: imageRank2 }, + { title: '[en]Quite a regular[/en][ja]常連[/ja]', min: 41, max: 70, special: false, image: imageRank3 }, + { title: '[en]Just can\'t stay away[/en][ja]一人前[/ja]', min: 71, max: 150, special: false, image: imageRank4 }, + { title: '[en]Home away from home[/en][ja]長老[/ja]', min: 151, max: 10000, special: false, image: imageRank5 }, + { title: '[en]Moderator[/en][ja]モデレータ[/ja]', min: 0, max: 0, special: true, image: imageRank6 }, + { title: '[en]Webmaster[/en][ja]管理人[/ja]', min: 0, max: 0, special: true, image: imageRank7 }, +]; + +const UserRankStarImage = (props: Props) => { + const { lang, rank, posts } = props; + const findRank = (posts: number) => { + const rank = userRanks.find((userRank) => { + if (posts >= userRank.min && posts <= userRank.max) { + return true; + } + return false; + }); + return typeof rank !== 'undefined' ? rank : userRanks[0]; + + } + const userRank = rank > 0 && rank <= 7 ? userRanks[rank - 1] : findRank(posts); + const title = Functions.mlang(userRank.title, lang); + return {title}; +} + +export default UserRankStarImage; \ No newline at end of file diff --git a/src/common/lib/XoopsCode.tsx b/src/common/lib/XoopsCode.tsx new file mode 100644 index 0000000..d101302 --- /dev/null +++ b/src/common/lib/XoopsCode.tsx @@ -0,0 +1,138 @@ +import React, { ReactElement } from 'react'; +import ReactHtmlParser, { convertNodeToElement } from 'react-html-parser'; +import { HashLink } from 'react-router-hash-link'; +import { MultiLang } from '../../config'; +import Functions from '../../functions'; + +interface Props { + lang: MultiLang; + text: string; + dohtml?: boolean; + dosmiley?: boolean; + doxcode?: boolean; + doimage?: boolean; + dobr?: boolean; +} + +const preConvertXCode = (text: string, doxcode: boolean): string => { + if (doxcode) { + return text.replace(/\[code\](.*)\[\/code\]/sg, (m0, m1) => { + return '[code]' + Functions.base64Encode(m1) + '[/code]'; + }); + } + return text; +} + +const postConvertXCode = (text: string, doxcode: boolean, doimage: boolean): string => { + if (doxcode) { + return text.replace(/\[code\](.*)\[\/code\]/sg, (m0, m1) => { + const text = convertXCode(Functions.htmlspecialchars(Functions.base64Decode(m1)), doimage); + return '
    ' + text + '
    '; + }); + } + return text; +} + +const convertClickable = (text: string) => { + text = text.replace(/(^|[^\]_a-zA-Z0-9-="'/]+)((?:https?|ftp)(?::\/\/[-_.!~*'()a-zA-Z0-9;/?:@&=+$,%#]+[a-zA-Z0-9=]))/g, (...matches) => { + return matches[1] + '' + matches[2] + ''; + }); + text = text.replace(/(^|[^\]_a-zA-Z0-9-="'/:.]+)([a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)+)/g, (...matches) => { + return matches[1] + '' + matches[2] + ''; + }); + return text; +} + +const convertXCode = (text: string, doimage: boolean): string => { + // TODO: implement + return text; +} + +const convertSmiley = (text: string) => { + // TODO: implement + return text; +} + +const convertBr = (text: string): string => { + return text.replace(/(\r?\n|\r)/g, '
    '); +} + +interface TransformParsedNode { + type: string; + next: object | null; + prev: object | null; + parent: object | null; + name: string; + attribs: any; + children: object[]; + data: string; +} + +const cssConvert = (text: string): object => { + const ret: any = {}; + text.split(';').forEach((line) => { + const line_ = line.trim(); + if (line.length === 0) { + return; + } + const kv = line_.split(':'); + const key = Functions.camelCase(kv[0].trim()); + const value = kv[1].trim(); + ret[key] = value; + }) + return ret; +} + +const transform = (node: object, idx: number): ReactElement | null | void => { + const node_ = node as TransformParsedNode; + if (node_.type === 'tag' && node_.name === 'a') { + const url = (node_.attribs && node_.attribs['href']) || '/'; + const download = (node_.attribs && node_.attribs['download']) || ''; + const rel = (node_.attribs && node_.attribs['rel']) || ''; + const isFile = download !== '' || url.match(/\.(zip|pdf|png|gif|jpg)$/); + const isExternal = /external/.test(rel) || /^(mailto|https?:?\/\/)/.test(url); + if (!isFile && !isExternal) { + const style = (node_.attribs && node_.attribs['style']) || ''; + const title = (node_.attribs && node_.attribs['title']) || null; + return + {node_.children.map((value: object, index: number) => { + return convertNodeToElement(value, index, transform); + })} + ; + } + } + if (node_.type === 'tag' && node_.name === 'img') { + const src = (node_.attribs && node_.attribs['src']) || ''; + node_.attribs['src'] = src.replace('`XOOPS_URL`', process.env.PUBLIC_URL); + return convertNodeToElement(node_ as object, idx, transform); + } +} + +const XoopsCode = (props: Props) => { + const { lang } = props; + let text = props.text; + const dohtml = !!props.dohtml; + const dosmiley = !!props.dosmiley; + const doxcode = !!props.doxcode; + const doimage = !!props.doimage; + const dobr = !!props.dobr; + text = preConvertXCode(text, doxcode); + if (!dohtml) { + text = Functions.htmlspecialchars(text); + text = convertClickable(text); + } + if (dosmiley) { + text = convertSmiley(text); + } + if (doxcode) { + text = convertXCode(text, doimage); + } + if (dobr) { + text = convertBr(text); + } + text = postConvertXCode(text, doxcode, doimage); + text = Functions.mlang(text, lang); + return
    {ReactHtmlParser(text, { transform })}
    ; +} + +export default XoopsCode; \ No newline at end of file diff --git a/src/config.ts b/src/config.ts new file mode 100644 index 0000000..d9725ae --- /dev/null +++ b/src/config.ts @@ -0,0 +1,17 @@ +const SITE_TITLE = 'Dynamic Brain Platform'; +const SITE_SLOGAN = 'Official Site'; +const GOOGLE_ANALYTICS_TRACKING_ID = 'UA-23709948-1'; +const XOONIPS_ITEMTYPES = ['model', 'data', 'tool', 'book', 'paper', 'conference', 'url', 'presentation', 'simulator', 'stimulus', 'memo', 'files', 'binder']; +const PICO_MODULES = ['documents', 'hackathon']; + +export type MultiLang = 'en' | 'ja'; + +const Config = { + SITE_TITLE, + SITE_SLOGAN, + GOOGLE_ANALYTICS_TRACKING_ID, + XOONIPS_ITEMTYPES, + PICO_MODULES, +} + +export default Config; diff --git a/src/credits/Credits.tsx b/src/credits/Credits.tsx new file mode 100644 index 0000000..d51997e --- /dev/null +++ b/src/credits/Credits.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import Helmet from 'react-helmet'; +import { Route, RouteComponentProps, Switch } from 'react-router-dom'; +import PageNotFound from '../common/lib/PageNotFound'; +import { MultiLang } from '../config'; +import Functions from '../functions'; +import CreditsAboutUs from './CreditsAboutUs'; +import CreditsPage from './CreditsPage'; +import CreditsUtils from './lib/CreditsUtils'; + +interface Props { + lang: MultiLang; +} + +const Credits = (props: Props) => { + const { lang } = props; + return ( + <> + + {CreditsUtils.getTitle(lang)} - {Functions.siteTitle(lang)} + + + } /> + ) => } /> + + + + ); +} + +export default Credits; diff --git a/src/credits/CreditsAboutUs.tsx b/src/credits/CreditsAboutUs.tsx new file mode 100644 index 0000000..fc52fae --- /dev/null +++ b/src/credits/CreditsAboutUs.tsx @@ -0,0 +1,24 @@ +import React from 'react'; +import XoopsCode from '../common/lib/XoopsCode'; +import { MultiLang } from '../config'; +import Functions from '../functions'; +import CreditsUtil from './lib/CreditsUtils'; +import NoticeSiteHasBeenArchived from '../common/lib/NoticeSiteHasBeenArchived'; + +interface Props { + lang: MultiLang; +} + +const CreditsAboutUs = (props: Props) => { + const { lang } = props; + const title = Functions.mlang(CreditsUtil.getAboutUsTitle(), lang); + return ( + <> +

    {title}

    + + + + ); +} + +export default CreditsAboutUs; diff --git a/src/credits/CreditsPage.tsx b/src/credits/CreditsPage.tsx new file mode 100644 index 0000000..288b7f2 --- /dev/null +++ b/src/credits/CreditsPage.tsx @@ -0,0 +1,46 @@ +import moment from 'moment'; +import React from 'react'; +import { RouteComponentProps } from 'react-router'; +import PageNotFound from '../common/lib/PageNotFound'; +import XoopsCode from '../common/lib/XoopsCode'; +import { MultiLang } from '../config'; +import Functions from '../functions'; +import CreditsUtils from './lib/CreditsUtils'; +import NoticeSiteHasBeenArchived from '../common/lib/NoticeSiteHasBeenArchived'; +import Helmet from 'react-helmet'; + +interface Params { + id: string; +} + +interface Props extends RouteComponentProps { + lang: MultiLang; +} + +const CreditsPage = (props: Props) => { + const { lang } = props; + const params = props.match.params; + if (params.id === '') { + return ; + } + const pageId = parseInt(props.match.params.id, 10); + const page = CreditsUtils.getPage(pageId); + if (page === null) { + return ; + } + const title = Functions.mlang(page.title, lang); + return ( + <> + + {title} - {Functions.siteTitle(lang)} + +

    {title}

    + +
    {Functions.mlang('[en]Last Update[/en][ja]最終更新日[/ja]', lang)} : {moment(new Date(page.lastupdate * 1000)).format('MMMM Do, YYYY')}
    +
    + + + ); +} + +export default CreditsPage; \ No newline at end of file diff --git a/src/credits/CreditsXoopsPathRedirect.tsx b/src/credits/CreditsXoopsPathRedirect.tsx new file mode 100644 index 0000000..97d34ac --- /dev/null +++ b/src/credits/CreditsXoopsPathRedirect.tsx @@ -0,0 +1,53 @@ +import React, { Component } from 'react'; +import { Redirect, RouteComponentProps, withRouter } from 'react-router'; +import PageNotFound from '../common/lib/PageNotFound'; +import { MultiLang } from '../config'; + +interface Props extends RouteComponentProps { + lang: MultiLang; +} + +class CreditsXoopsPathRedirect extends Component { + + getRedirectUrl(): string { + const { location } = this.props; + const name = 'credits'; + const pathname = location.pathname || ''; + const query = new URLSearchParams(location.search); + const search = new RegExp(`^/modules/${name}(?:/+(.*))?$`); + const matches = pathname.match(search); + if (matches === null) { + return ''; + } + const path = matches[1] || ''; + switch (path) { + case '': + case 'index.php': { + const id = query.get('id'); + if (id !== null) { + if (id.match(/^\d+$/) !== null) { + return '/' + name + '/' + id; + } + return ''; + } + return '/' + name; + + } + case 'aboutus.php': { + return '/' + name; + } + } + return ''; + } + + render() { + const { lang } = this.props; + const url = this.getRedirectUrl(); + if (url === '') { + return ; + } + return ; + } +} + +export default withRouter(CreditsXoopsPathRedirect); diff --git a/src/credits/block/CreditsMenu.tsx b/src/credits/block/CreditsMenu.tsx new file mode 100644 index 0000000..8f2de78 --- /dev/null +++ b/src/credits/block/CreditsMenu.tsx @@ -0,0 +1,27 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { MultiLang } from '../../config'; +import Functions from '../../functions'; +import CreditsUtils from '../lib/CreditsUtils'; + +interface Props { + lang: MultiLang; + showAboutUs?: boolean; +} + +const CreditsMenu = (props: Props) => { + const { lang, showAboutUs = true } = props; + const menu = CreditsUtils.getMenu(showAboutUs); + const links = menu.map((item, idx) => { + const title = Functions.mlang(item.title, lang); + const style = idx === 0 ? 'menuTop' : 'menuMain'; + return
  • {title}
  • + }); + return ( +
      + {links} +
    + ); +} + +export default CreditsMenu; diff --git a/src/credits/lib/CreditsUtils.ts b/src/credits/lib/CreditsUtils.ts new file mode 100644 index 0000000..5691ebc --- /dev/null +++ b/src/credits/lib/CreditsUtils.ts @@ -0,0 +1,73 @@ +import { MultiLang } from '../../config'; +import Functions from '../../functions'; +import creditsJson from '../assets/credits.json'; + +export interface CreditsPageData { + pid: number; + title: string; + content: string; + lastupdate: number; +} + +interface CreditsData { + organization: string; + pages: CreditsPageData[]; +} + +export interface CreditsMenu { + title: string; + link: string; +} + +class CreditsUtils { + private data: CreditsData; + + constructor(json: CreditsData) { + this.data = json; + } + + getTitle(lang: MultiLang): string { + return Functions.mlang('[en]Site Information[/en][ja]サイト情報[/ja]', lang); + } + + getIndexUrl(): string { + return '/credits'; + } + + getPageUrl(pageId: number): string { + return this.getIndexUrl() + '/' + pageId; + } + + getMenu(showAboutUs: boolean): CreditsMenu[] { + const menu: CreditsMenu[] = []; + this.data.pages.forEach((page) => { + menu.push({ title: page.title, link: this.getPageUrl(page.pid) }); + }); + if (showAboutUs) { + menu.push({ title: this.getAboutUsTitle(), link: this.getIndexUrl() }); + } + return menu; + } + + getPage(pageId: number): CreditsPageData | null { + const page = this.data.pages.find((page) => { return page.pid === pageId; }); + if (typeof page === 'undefined') { + return null; + } + return page; + } + + countPages(): number { + return this.data.pages.length; + } + + getAboutUsTitle(): string { + return 'About Us'; + } + + getAboutUsContent(): string { + return this.data.organization; + } +} + +export default new CreditsUtils(creditsJson); \ No newline at end of file diff --git a/src/custom/blocks/Welcome.tsx b/src/custom/blocks/Welcome.tsx new file mode 100644 index 0000000..7469498 --- /dev/null +++ b/src/custom/blocks/Welcome.tsx @@ -0,0 +1,78 @@ +import React from 'react'; +import NoticeSiteHasBeenArchived from '../../common/lib/NoticeSiteHasBeenArchived'; +import { MultiLang } from '../../config'; +import Functions from '../../functions'; +import { Link } from 'react-router-dom'; + +interface Props { + lang: MultiLang; +} + +const articles = { + en: [ + { + title: 'Minoru Tsukada, Memory and Learning mechanism in the Hippocampal Network', + link: '/mediawiki/Memory_and_Learning_mechanism_in_the_Hippocampal_Network' + }, + { + title: 'Yoko Yamaguchi, Theta Rhythm and Memory Formation in Rat Hippocampus', + link: '/mediawiki/Theta_Rhythm_and_Memory_Formation_in_Rat_Hippocampus' + }, + { + title: 'Hatsuo Hayashi, Dynamical features of neurons and the brain: Chaos, synchronization, and propagation', + link: '/mediawiki/Dynamical_features_of_neurons_and_the_brain:_Chaos,_synchronization,_and_propagation' + }, + { + title: 'Ichiro Tsuda, Computational Life Science', + link: '/mediawiki/Computational_Life_Science' + }, + { + title: 'Yutaka Sakai, From synapse to behavior', + link: '/mediawiki/From_synapse_to_behavior' + }, + ], + ja: [ + { + title: '塚田稔「学習と記憶の理論的・実験的研究」', + link: '/mediawiki/学習と記憶の理論的・実験的研究' + }, + { + title: '山口陽子「ラット海馬のシータリズムと記憶形成」', + link: '/mediawiki/ラット海馬のシータリズムと記憶形成' + }, + { + title: '林初男「ニューロンと脳のダイナミクス:カオス、同期、伝搬」', + link: '/mediawiki/ニューロンと脳のダイナミクス:カオス、同期、伝搬' + }, + { + title: '津田一郎 「Computational Life Science」', + link: '/mediawiki/Computational_Life_Science' + }, + { + title: '酒井裕「シナプスから行動へ」 ', + link: '/mediawiki/From_synapse_to_behavior' + }, + ] +}; + +const Welcome = (props: Props) => { + const { lang } = props; + return ( +
    + +

    {Functions.mlang('[en]This site promotes studies on the dynamic principles of brain functions through unifying experimental and computational approaches in cellular, local circuit, global network and behavioral levels. Our goal is to capture the autonomy and the creativity in living organisms which enlightens the complexity of nature and society.[/en][ja]当サイトでは、脳の動的原理を解明することを目的として、細胞、局所回路、脳全域、行動などの様々なレベルでの実験的計算論的アプローチの統合的な研究を推進します。これらの研究から生命の自律性と情報創成の原理を捉え、さらに自然や人間社会の複雑性の理解を進めることを目指します。[/ja]', lang)}

    +

    {Functions.mlang('[en]Feature Articles[/en][ja]特集記事[/ja]', lang)}

    +
      + {articles[lang].map((i) => { + return
    • {i.title}
    • ; + })} +
    +

    {Functions.mlang('[en]Announcements[/en][ja]お知らせ[/ja]', lang)}

    +

    + NIX-odML Global Workshop & Hackathon 2017 in Japan ({Functions.mlang('[en]Sept. 25-28, 2017[/en][ja]2017年9月25-28日[/ja]', lang)}) +

    +
    + ); +} + +export default Welcome; \ No newline at end of file diff --git a/src/database/Database.module.css b/src/database/Database.module.css new file mode 100644 index 0000000..8ea86ba --- /dev/null +++ b/src/database/Database.module.css @@ -0,0 +1,70 @@ +.database { + margin: 0; +} + +.database :global(.list) { + width: 100%; +} + +.database :global(.listTable) { + width: 100%; + border-collapse: separate; + border-spacing: 5px; +} + +.database :global(.listTable .listIcon), +.database :global(.listTable .listExtra) { + vertical-align: middle; + text-align: center; + width: 65px; + line-height: 0; +} + +.database :global(.itemDetail) { + border-collapse: separate; + border-spacing: 1px; +} +.database :global(.itemDetail .head) { + width: 30%; +} + +.database :global(.itemDetail .readme), +.database :global(.itemDetail .rights) { + background-color: #ffffff; + width: 100%; + max-height: 200px; + overflow: auto; +} + +.database :global(.advancedSearch .head) { + width: 30%; +} + +.database :global(.advancedSearch .search) { + text-align: center; + margin: 10px; +} + +.database :global(.advancedSearch .itemtype) { + margin-bottom: 5px; +} + +.database :global(.advancedSearch .itemtype .itemtypeName), +.database :global(.advancedSearch .itemtype .itemtypeFields) { + border-collapse: separate; + border-spacing: 1px; +} + +.database :global(.advancedSearch .itemtype .itemtypeName th) { + padding: 5px; +} + +.database :global(.advancedSearch .fieldDateLabel) { + display: inline-block; + width: 50px; +} + +.database :global(.advancedSearch .fieldDate select), +.database :global(.advancedSearch .fieldDate input) { + margin: 0 5px 0 0; +} diff --git a/src/database/Database.tsx b/src/database/Database.tsx new file mode 100644 index 0000000..51a6e3a --- /dev/null +++ b/src/database/Database.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import Helmet from 'react-helmet'; +import { Route, RouteComponentProps, Switch } from 'react-router-dom'; +import PageNotFound from '../common/lib/PageNotFound'; +import { MultiLang } from '../config'; +import Functions from '../functions'; +import styles from './Database.module.css'; +import DatabaseAdvancedSearch from './DatabaseAdvancedSearch'; +import DatabaseDetailItem from './DatabaseDetailItem'; +import DatabaseSearchByAdvancedKeyword from './DatabaseSearchByAdvancedKeyword'; +import DatabaseSearchByIndexId from './DatabaseSearchByIndexId'; +import DatabaseSearchByItemType from './DatabaseSearchByItemType'; +import DatabaseSearchByKeyword from './DatabaseSearchByKeyword'; +import DatabaseTop from './DatabaseTop'; + +interface Props { + lang: MultiLang; +} + +const Database = (props: Props) => { + const { lang } = props; + return ( +
    + + {Functions.mlang('[en]Database[/en][ja]データベース[/ja]', lang)} - {Functions.siteTitle(lang)} + + + } /> + ) => } /> + ) => } /> + } /> + ) => } /> + ) => } /> + } /> + } /> + ) => } /> + ) => } /> + + +
    + ); +} + +export default Database; \ No newline at end of file diff --git a/src/database/DatabaseAdvancedSearch.tsx b/src/database/DatabaseAdvancedSearch.tsx new file mode 100644 index 0000000..6375e4c --- /dev/null +++ b/src/database/DatabaseAdvancedSearch.tsx @@ -0,0 +1,48 @@ +import React, { Component } from 'react'; +import { RouteComponentProps } from 'react-router'; +import Config, { MultiLang } from '../config'; +import Functions from '../functions'; +import ItemType from './item-type'; +import AdvancedSearchQuery from './lib/AdvancedSearchQuery'; +import ItemUtil from './lib/ItemUtil'; + +interface Props extends RouteComponentProps { + lang: MultiLang; +} + +class DatabaseAdvancedSearch extends Component { + + private query: AdvancedSearchQuery = new AdvancedSearchQuery(); + + constructor(props: Props) { + super(props); + this.handleClickSearchButton = this.handleClickSearchButton.bind(this); + } + + handleClickSearchButton() { + if (!this.query.empty()) { + const url = ItemUtil.getSearchByAdvancedKeywordsUrl(this.query); + this.props.history.push(url); + } + } + + render() { + const { lang } = this.props; + return ( +
    +

    {Functions.mlang('[en]Search Items[/en][ja]アイテム検索[/ja]', lang)}

    +
    + +
    + {Config.XOONIPS_ITEMTYPES.map((type) => { + return ; + })} +
    + +
    +
    + ); + } +} + +export default DatabaseAdvancedSearch; \ No newline at end of file diff --git a/src/database/DatabaseDetailItem.tsx b/src/database/DatabaseDetailItem.tsx new file mode 100644 index 0000000..74dfa1a --- /dev/null +++ b/src/database/DatabaseDetailItem.tsx @@ -0,0 +1,89 @@ +import React, { Component } from 'react'; +import Helmet from 'react-helmet'; +import { RouteComponentProps } from 'react-router'; +import Loading from '../common/lib/Loading'; +import PageNotFound from '../common/lib/PageNotFound'; +import { MultiLang } from '../config'; +import Functions from '../functions'; +import ItemType from './item-type'; +import ItemUtil, { Item } from './lib/ItemUtil'; + +interface Params { + id: string; + doi: string; +} + +interface Props extends RouteComponentProps { + lang: MultiLang; +} + +interface State { + loading: boolean; + item: Item | null; +} + +class DatabaseDetailItem extends Component { + + private id: number; + private doi: string; + + constructor(props: Props) { + super(props); + this.state = { + loading: true, + item: null, + }; + const { params } = this.props.match; + this.id = typeof params.id !== 'undefined' ? (params.id.match(/^\d+$/) !== null ? parseInt(params.id, 10) : 0) : 0; + this.doi = typeof params.doi !== 'undefined' ? params.doi : ''; + } + + componentDidMount() { + this.updateItem(); + } + + componentDidUpdate() { + const { params } = this.props.match; + const id = typeof params.id !== 'undefined' ? (params.id.match(/^\d+$/) !== null ? parseInt(params.id, 10) : 0) : 0; + const doi = typeof params.doi !== 'undefined' ? params.doi : ''; + if (this.id !== id || this.doi !== doi) { + this.id = id; + this.doi = doi; + this.updateItem(); + } + } + + updateItem() { + if (this.doi !== '') { + ItemUtil.getByDoi(this.doi, (item) => { + this.setState({ loading: false, item }); + }); + } else if (this.id !== 0) { + ItemUtil.get(this.id, (item) => { + this.setState({ loading: false, item }); + }); + } + } + + render() { + const { lang } = this.props; + if (this.state.loading) { + return ; + } + if (this.state.item === null) { + return ; + } + return ( + <> + + {Functions.mlang(this.state.item.title, lang)} - {Functions.mlang('[en]Database[/en][ja]データベース[/ja]', lang)} - {Functions.siteTitle(lang)} + +

    {Functions.mlang('[en]Detail[/en][ja]詳細[/ja]', lang)}

    +
    + + + ); + } +} + +export default DatabaseDetailItem; \ No newline at end of file diff --git a/src/database/DatabaseSearchByAdvancedKeyword.tsx b/src/database/DatabaseSearchByAdvancedKeyword.tsx new file mode 100644 index 0000000..72427aa --- /dev/null +++ b/src/database/DatabaseSearchByAdvancedKeyword.tsx @@ -0,0 +1,56 @@ +import React, { Component } from 'react'; +import { RouteComponentProps } from 'react-router'; +import { MultiLang } from '../config'; +import AdvancedSearchQuery from './lib/AdvancedSearchQuery'; +import DatabaseListItem from './lib/DatabaseListItem'; +import ItemUtil, { SearchCallbackFunc, SortCondition } from './lib/ItemUtil'; + +interface Props extends RouteComponentProps { + lang: MultiLang +} + +interface State { + search: string; + query: AdvancedSearchQuery; +} + +class DatabaseSearchByAdvancedKeyword extends Component { + + constructor(props: Props) { + super(props); + const search = props.location.search; + const query = ItemUtil.getAdvancedSearchQueryByQuery(search); + this.state = { search, query }; + this.searchFunc = this.searchFunc.bind(this); + } + + static getDerivedStateFromProps(nextProps: Props, prevState: State) { + const search = nextProps.location.search; + if (prevState.search !== search) { + const query = ItemUtil.getAdvancedSearchQueryByQuery(search); + return { search, query }; + } + return null; + } + + getUrl() { + return ItemUtil.getSearchByAdvancedKeywordsUrl(this.state.query); + } + + searchFunc(condition: SortCondition, func: SearchCallbackFunc) { + ItemUtil.getListByAdvancedSearchQuery(this.state.query, condition, func); + } + + render() { + const { lang } = this.props; + const baseUrl = this.getUrl(); + return ( +
    +

    Listing item

    + +
    + ); + } +} + +export default DatabaseSearchByAdvancedKeyword; diff --git a/src/database/DatabaseSearchByIndexId.tsx b/src/database/DatabaseSearchByIndexId.tsx new file mode 100644 index 0000000..8e81783 --- /dev/null +++ b/src/database/DatabaseSearchByIndexId.tsx @@ -0,0 +1,88 @@ +import React, { Component, Fragment } from 'react'; +import Helmet from 'react-helmet'; +import { RouteComponentProps } from 'react-router'; +import { Link } from 'react-router-dom'; +import PageNotFound from '../common/lib/PageNotFound'; +import { MultiLang } from '../config'; +import Functions from '../functions'; +import DatabaseListIndex from './lib/DatabaseListIndex'; +import DatabaseListItem from './lib/DatabaseListItem'; +import IndexUtil, { Index, INDEX_ID_PUBLIC } from './lib/IndexUtil'; +import ItemUtil, { SearchCallbackFunc, SortCondition } from './lib/ItemUtil'; + +interface Params { + id: string; +} + +export interface Props extends RouteComponentProps { + lang: MultiLang; +} + +interface State { + indexId: number; +} + +class DatabaseSearchByIndexId extends Component { + + constructor(props: Props) { + super(props); + const { params } = props.match; + this.state = { + indexId: params.id ? (params.id.match(/^\d+$/) !== null ? parseInt(params.id, 10) : 0) : INDEX_ID_PUBLIC, + } + this.searchFunc = this.searchFunc.bind(this); + } + + static getDerivedStateFromProps(nextProps: Props, prevState: State) { + const { params } = nextProps.match; + const indexId = params.id ? (params.id.match(/^\d+$/) !== null ? parseInt(params.id, 10) : 0) : INDEX_ID_PUBLIC; + if (prevState.indexId !== indexId) { + return { indexId }; + } + return null; + } + + getUrl() { + if (this.state.indexId === 0) { + return '/'; + } + return IndexUtil.getUrl(this.state.indexId); + } + + searchFunc(condition: SortCondition, func: SearchCallbackFunc) { + if (this.state.indexId === 0) { + const res = { total: 0, data: [] }; + func(res); + } else { + ItemUtil.getListByIndexId(this.state.indexId, condition, func); + } + } + + render() { + const { lang } = this.props; + const index = IndexUtil.get(this.state.indexId); + if (index === null) { + return ; + } + const baseUrl = this.getUrl(); + const pIndexes = IndexUtil.getParents(this.state.indexId); + const parents = pIndexes.map((value: Index) => { + const url: string = IndexUtil.getUrl(value.id); + return / {value.title} ; + }); + const title = pIndexes.map((value) => { return '/' + value.title; }).join(''); + return ( +
    + + {Functions.mlang(title, lang)} - {Functions.mlang('[en]Database[/en][ja]データベース[/ja]', lang)} - {Functions.siteTitle(lang)} + +

    {Functions.mlang('[en]Listing item[/en][ja]アイテム一覧[/ja]', lang)}

    +
    {parents}
    + + +
    + ); + } +} + +export default DatabaseSearchByIndexId; diff --git a/src/database/DatabaseSearchByItemType.tsx b/src/database/DatabaseSearchByItemType.tsx new file mode 100644 index 0000000..257538b --- /dev/null +++ b/src/database/DatabaseSearchByItemType.tsx @@ -0,0 +1,73 @@ +import React, { Component } from 'react'; +import { RouteComponentProps } from 'react-router'; +import { MultiLang } from '../config'; +import Functions from '../functions'; +import DatabaseListItem from './lib/DatabaseListItem'; +import ItemUtil, { SearchCallbackFunc, SortCondition } from './lib/ItemUtil'; + +interface Params { + itemType: string; + subItemType: string; +} + +interface Props extends RouteComponentProps { + lang: MultiLang; +} + +interface State { + itemType: string; + subItemType: string; +} + +class DatabaseSearchByItemType extends Component { + + constructor(props: Props) { + super(props); + const { params } = this.props.match; + this.state = { + itemType: params.itemType ? params.itemType : '', + subItemType: params.subItemType ? params.subItemType : '', + }; + this.searchFunc = this.searchFunc.bind(this); + } + + static getDerivedStateFromProps(nextProps: Props, prevState: State) { + const { params } = nextProps.match; + const item_type = params.itemType ? params.itemType : ''; + const sub_item_type = params.subItemType ? params.subItemType : ''; + if (prevState.itemType !== item_type || prevState.subItemType !== sub_item_type) { + return { item_type, sub_item_type }; + } + return null; + } + + searchFunc(condition: SortCondition, func: SearchCallbackFunc) { + if (this.state.itemType === '') { + const res = { total: 0, data: [] }; + func(res); + } else { + ItemUtil.getListByItemType(this.state.itemType, this.state.subItemType, condition, func); + } + } + + getUrl() { + let url = ItemUtil.getItemTypeSearchUrl(this.state.itemType); + if (this.state.subItemType !== '') { + url += '/' + this.state.subItemType; + } + return url; + } + + render() { + const { lang } = this.props; + const baseUrl = this.getUrl(); + return ( +
    +

    {Functions.mlang('[en]Listing item[/en][ja]アイテム一覧[/ja]', lang)}

    + +
    + ); + } +} + +export default DatabaseSearchByItemType; diff --git a/src/database/DatabaseSearchByKeyword.tsx b/src/database/DatabaseSearchByKeyword.tsx new file mode 100644 index 0000000..8961fd8 --- /dev/null +++ b/src/database/DatabaseSearchByKeyword.tsx @@ -0,0 +1,60 @@ +import React, { Component } from 'react'; +import { RouteComponentProps } from 'react-router'; +import { MultiLang } from '../config'; +import Functions from '../functions'; +import DatabaseListItem from './lib/DatabaseListItem'; +import ItemUtil, { KeywordSearchType, SearchCallbackFunc, SortCondition } from './lib/ItemUtil'; + +interface Props extends RouteComponentProps { + lang: MultiLang; +} + +interface State { + type: KeywordSearchType; + keyword: string; +} + +class DatabaseSearchByKeyword extends Component { + + constructor(props: Props) { + super(props); + const { type, keyword } = ItemUtil.getSearchKeywordByQuery(this.props.location.search); + this.state = { type, keyword }; + this.searchFunc = this.searchFunc.bind(this); + } + + static getDerivedStateFromProps(nextProps: Props, prevState: State) { + const { type, keyword } = ItemUtil.getSearchKeywordByQuery(nextProps.location.search); + if (prevState.type !== type || prevState.keyword !== keyword) { + return { type, keyword }; + } + return null; + } + + getUrl() { + return ItemUtil.getSearchByKeywordUrl(this.state.type, this.state.keyword); + } + + searchFunc(condition: SortCondition, func: SearchCallbackFunc) { + if (this.state.keyword === '') { + const res = { total: 0, data: [] }; + func(res); + } else { + ItemUtil.getListByKeyword(this.state.type, this.state.keyword, condition, func); + } + } + + render() { + const { lang } = this.props; + const baseUrl = this.getUrl(); + return ( +
    +

    {Functions.mlang('[en]Listing item[/en][ja]アイテム一覧[/ja]', lang)}

    +

    {Functions.mlang('[en]Search Keyword[/en][ja]検索キーワード[/ja]', lang)} : {this.state.keyword}

    + +
    + ); + } +} + +export default DatabaseSearchByKeyword; diff --git a/src/database/DatabaseTop.module.css b/src/database/DatabaseTop.module.css new file mode 100644 index 0000000..a89d26d --- /dev/null +++ b/src/database/DatabaseTop.module.css @@ -0,0 +1,13 @@ +.itemTypes .itemType { + width: 50%; + padding: 5px; +} + +.itemTypes .itemType :global(table) { + width: auto; +} + +.itemTypes .itemType :global(table .itemTypeName) { + vertical-align: middle; + font-size: large; +} \ No newline at end of file diff --git a/src/database/DatabaseTop.tsx b/src/database/DatabaseTop.tsx new file mode 100644 index 0000000..3e88a06 --- /dev/null +++ b/src/database/DatabaseTop.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import Config, { MultiLang } from '../config'; +import styles from './DatabaseTop.module.css'; +import ItemType from './item-type'; + +interface Props { + lang: MultiLang; +} + +const DatabaseTop = (props: Props) => { + const { lang } = props; + const types: string[][] = []; + const len = Config.XOONIPS_ITEMTYPES.length; + for (let i = 0; i < Math.ceil(len / 2); i++) { + const j = i * 2; + const p = Config.XOONIPS_ITEMTYPES.slice(j, j + 2); + types.push(p); + } + return ( + + + {types.map((value, idx) => { + return ( + + {value.map((type, idx) => { + return ( + + ); + })} + + ); + })} + +
    + {type !== '' && } +
    + ); +} + +export default DatabaseTop; diff --git a/src/database/DatabaseXoopsPathRedirect.tsx b/src/database/DatabaseXoopsPathRedirect.tsx new file mode 100644 index 0000000..a38c0d2 --- /dev/null +++ b/src/database/DatabaseXoopsPathRedirect.tsx @@ -0,0 +1,150 @@ +import React, { Component } from 'react'; +import { Redirect, RouteComponentProps, withRouter } from 'react-router'; +import PageNotFound from '../common/lib/PageNotFound'; +import { MultiLang } from '../config'; +import Functions from '../functions'; + +interface Props extends RouteComponentProps { + lang: MultiLang; +} + +class DatabaseXoopsPathRedirect extends Component { + + getRedirectUrl(): string { + const { location } = this.props; + const pathname = location.pathname || ''; + const query = new URLSearchParams(location.search); + const search = new RegExp('^/modules/xoonips(?:/+(.*))?$'); + const matches = pathname.match(search); + if (matches === null) { + return ''; + } + const path = matches[1] || ''; + switch (path) { + case '': + case 'index.php': { + return '/database'; + } + case 'detail.php': { + const id = query.get('id'); + if (id !== null) { + return '/database/item/id/' + Functions.escape(id); + } + const itemId = query.get('item_id'); + if (itemId !== null && itemId.match(/^\d+$/) !== null) { + return '/database/item/' + Functions.escape(itemId); + } + return ''; + } + case 'listitem.php': { + const indexId = query.get('index_id'); + if (indexId !== null && indexId.match(/^\d+$/) !== null) { + const params = new URLSearchParams(); + const map: any = { + orderby: { key: 'orderby', isNumber: false }, + order_dir: { key: 'order_dir', isNumber: true }, + itemcount: { key: 'itemcount', isNumber: true }, + page: { key: 'page', isNumber: true } + }; + for (let k in map) { + const v = query.get(k); + if (v === null || v.length === 0) { + continue; + } + if (map[k].isNumber && v.match(/^\d+$/) !== null) { + continue; + } + params.set(map[k].key, v); + } + const paramStr = params.toString(); + return '/database/list/' + Functions.escape(indexId) + (paramStr.length > 0 ? '?' + paramStr : ''); + } + break; + } + case 'itemselect.php': { + const op = query.get('op'); + if (op === null) { + break; + } + switch (op) { + case 'quicksearch': { + const keyword = query.get('keyword'); + const itemType = query.get('search_itemtype'); + if (keyword === null || itemType === null || keyword === '') { + return ''; + } + const type = itemType.replace('xnp', ''); + if (itemType !== 'basic' && itemType !== 'all' && itemType.match(/^xnp.+/) === null) { + return ''; + } + const params = new URLSearchParams({ type, keyword }); + const map: any = { + orderby: { key: 'orderby', isNumber: false }, + orderdir: { key: 'order_dir', isNumber: true }, + item_per_page: { key: 'itemcount', isNumber: true }, + page: { key: 'page', isNumber: true } + }; + for (let k in map) { + const v = query.get(k); + if (v === null || v.length === 0) { + continue; + } + if (map[k].isNumber && v.match(/^\d+$/) !== null) { + continue; + } + params.set(map[k].key, v); + } + return '/database/search?' + params.toString(); + } + case 'itemtypesearch': { + const itemType = query.get('search_itemtype'); + if (itemType === null || itemType.match(/^xnp.+/) === null) { + return ''; + } + const type = itemType.replace('xnp', ''); + return '/database/search/itemtype/' + Functions.escape(type); + } + case 'itemsubtypesearch': { + let type = ''; + let subtype = ''; + query.forEach((v, k) => { + if (k.match(/^xnp[a-z]+$/) !== null && !!v) { + type = k.replace('xnp', ''); + return; + } + }) + if (type === '') { + return ''; + } + query.forEach((v, k) => { + if (k.match(`^xnp${type}_.+$`) !== null && !!v) { + subtype = v; + return; + } + }); + if (subtype === '') { + return ''; + } + return '/database/search/itemtype/' + Functions.escape(type) + '/' + Functions.escape(subtype); + } + } + return ''; + } + case 'advanced_search.php': { + return '/database/advanced'; + } + } + return ''; + } + + render() { + const { lang } = this.props; + const url = this.getRedirectUrl(); + if (url === '') { + return ; + } + return ; + } +} + +export default withRouter(DatabaseXoopsPathRedirect); diff --git a/src/database/assets/images/icon_binder.gif b/src/database/assets/images/icon_binder.gif new file mode 100644 index 0000000..c438f03 Binary files /dev/null and b/src/database/assets/images/icon_binder.gif differ diff --git a/src/database/assets/images/icon_book.gif b/src/database/assets/images/icon_book.gif new file mode 100644 index 0000000..6deea1b Binary files /dev/null and b/src/database/assets/images/icon_book.gif differ diff --git a/src/database/assets/images/icon_conference.gif b/src/database/assets/images/icon_conference.gif new file mode 100644 index 0000000..ec56f37 Binary files /dev/null and b/src/database/assets/images/icon_conference.gif differ diff --git a/src/database/assets/images/icon_data.gif b/src/database/assets/images/icon_data.gif new file mode 100644 index 0000000..30d35c8 Binary files /dev/null and b/src/database/assets/images/icon_data.gif differ diff --git a/src/database/assets/images/icon_files.gif b/src/database/assets/images/icon_files.gif new file mode 100644 index 0000000..e102eea Binary files /dev/null and b/src/database/assets/images/icon_files.gif differ diff --git a/src/database/assets/images/icon_folder.gif b/src/database/assets/images/icon_folder.gif new file mode 100644 index 0000000..7a69a82 Binary files /dev/null and b/src/database/assets/images/icon_folder.gif differ diff --git a/src/database/assets/images/icon_memo.gif b/src/database/assets/images/icon_memo.gif new file mode 100644 index 0000000..e6b4cd1 Binary files /dev/null and b/src/database/assets/images/icon_memo.gif differ diff --git a/src/database/assets/images/icon_model.gif b/src/database/assets/images/icon_model.gif new file mode 100644 index 0000000..493d673 Binary files /dev/null and b/src/database/assets/images/icon_model.gif differ diff --git a/src/database/assets/images/icon_paper.gif b/src/database/assets/images/icon_paper.gif new file mode 100644 index 0000000..d01d631 Binary files /dev/null and b/src/database/assets/images/icon_paper.gif differ diff --git a/src/database/assets/images/icon_presentation.gif b/src/database/assets/images/icon_presentation.gif new file mode 100644 index 0000000..c7e1b31 Binary files /dev/null and b/src/database/assets/images/icon_presentation.gif differ diff --git a/src/database/assets/images/icon_simulator.gif b/src/database/assets/images/icon_simulator.gif new file mode 100644 index 0000000..a9f359e Binary files /dev/null and b/src/database/assets/images/icon_simulator.gif differ diff --git a/src/database/assets/images/icon_stimulus.gif b/src/database/assets/images/icon_stimulus.gif new file mode 100644 index 0000000..09de6b8 Binary files /dev/null and b/src/database/assets/images/icon_stimulus.gif differ diff --git a/src/database/assets/images/icon_tool.gif b/src/database/assets/images/icon_tool.gif new file mode 100644 index 0000000..b71b3f6 Binary files /dev/null and b/src/database/assets/images/icon_tool.gif differ diff --git a/src/database/assets/images/icon_url.gif b/src/database/assets/images/icon_url.gif new file mode 100644 index 0000000..e4f1dfa Binary files /dev/null and b/src/database/assets/images/icon_url.gif differ diff --git a/src/database/assets/images/simpf_button.png b/src/database/assets/images/simpf_button.png new file mode 100644 index 0000000..1f93ad6 Binary files /dev/null and b/src/database/assets/images/simpf_button.png differ diff --git a/src/database/assets/images/star.gif b/src/database/assets/images/star.gif new file mode 100644 index 0000000..f90543e Binary files /dev/null and b/src/database/assets/images/star.gif differ diff --git a/src/database/assets/images/tree_line.png b/src/database/assets/images/tree_line.png new file mode 100644 index 0000000..2865cd2 Binary files /dev/null and b/src/database/assets/images/tree_line.png differ diff --git a/src/database/assets/images/tree_node.png b/src/database/assets/images/tree_node.png new file mode 100644 index 0000000..b23e4b1 Binary files /dev/null and b/src/database/assets/images/tree_node.png differ diff --git a/src/database/blocks/IndexTree.module.css b/src/database/blocks/IndexTree.module.css new file mode 100644 index 0000000..7ff982f --- /dev/null +++ b/src/database/blocks/IndexTree.module.css @@ -0,0 +1,90 @@ +.indexTree { + border-top: 1px solid #999999; + border-left: 1px solid #999999; + border-bottom: 1px solid #404040; + border-right: 1px solid #404040; + background-color: white; + height: 400px; + width: calc(100% - 8px); + overflow: auto; + padding: 3px; + line-height: 100%; +} + +.formButton { + margin: 3px 3px 10px; +} + +.indexTree div span { + color: #333; + font-size: 12px; + font-weight: bold; + line-height: 19px; + vertical-align: bottom; +} + +.indexTree div span:hover { + color: #f60; +} + +.indexTree:global(.rc-tree .rc-tree-treenode) { + line-height: 20px; + white-space: nowrap; +} +.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-indent) { + display: inline-block; +} +.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-indent .rc-tree-indent-unit) { + display: inline-block; + height: 20px; + width: 9px; + background: url(../assets/images/tree_line.png); +} +.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-indent .rc-tree-indent-unit:not(:last-child)) { + background-position: -9px 0; +} +.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-indent .rc-tree-indent-unit:not(:last-child).rc-tree-indent-unit-end) { + background-position: -18px 0; +} +.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-indent .rc-tree-indent-unit:last-child.rc-tree-indent-unit-end) { + background-position: -27px 0; +} + +.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-switcher) { + display: inline-block; + height: 20px; + width: 16px; + margin-right: 2px; + background: url(../assets/images/tree_node.png); + cursor: pointer; +} +.indexTree:global(.rc-tree .rc-tree-treenode:first-child .rc-tree-switcher.rc-tree-switcher-noop) { + background-position: 0 0; + cursor: auto; +} +.indexTree:global(.rc-tree .rc-tree-treenode:first-child .rc-tree-switcher.rc-tree-switcher_open) { + background-position: -16px 0; +} +.indexTree:global(.rc-tree .rc-tree-treenode:first-child .rc-tree-switcher.rc-tree-switcher_close) { + background-position: -32px 0; +} +.indexTree:global(.rc-tree .rc-tree-treenode:not(:first-child) .rc-tree-switcher.rc-tree-switcher-noop) { + background-position: 0 -20px; + cursor: auto; +} +.indexTree:global(.rc-tree .rc-tree-treenode:not(:first-child) .rc-tree-switcher.rc-tree-switcher_open) { + background-position: -16px -20px; +} +.indexTree:global(.rc-tree .rc-tree-treenode:not(:first-child) .rc-tree-switcher.rc-tree-switcher_close) { + background-position: -32px -20px; +} + +.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-node-content-wrapper) { + display: inline-block; + height: 20px; + cursor: pointer; +} +.indexTree:global(.rc-tree .rc-tree-treenode .rc-tree-node-content-wrapper .rc-tree-title) { + vertical-align: middle; + line-height: 20px; +} \ No newline at end of file diff --git a/src/database/blocks/IndexTree.tsx b/src/database/blocks/IndexTree.tsx new file mode 100644 index 0000000..3a43c76 --- /dev/null +++ b/src/database/blocks/IndexTree.tsx @@ -0,0 +1,113 @@ +import Tree from 'rc-tree'; +import { DataNode, NodeInstance } from 'rc-tree/lib/interface'; +import React, { Component } from 'react'; +import { RouteComponentProps, withRouter } from 'react-router'; +import { MultiLang } from '../../config'; +import Functions from '../../functions'; +import IndexUtil, { Index, INDEX_ID_PUBLIC } from '../lib/IndexUtil'; +import styles from './IndexTree.module.css'; + +interface Props extends RouteComponentProps { + lang: MultiLang; +} + +interface State { + tree: DataNode[]; + expandableKeys: string[]; + expandedKeys: string[]; + selectedKeys: number[]; +} + +class IndexTree extends Component { + + constructor(props: Props) { + super(props); + this.handleClickOpenAll = this.handleClickOpenAll.bind(this); + this.handleClickCloseAll = this.handleClickCloseAll.bind(this); + this.handleExpand = this.handleExpand.bind(this); + this.handleSelect = this.handleSelect.bind(this); + const res = this.load(); + this.state = { + tree: res.elements, + expandableKeys: res.keys, + expandedKeys: res.expandedKeys, + selectedKeys: [], + }; + } + + load() { + const { lang } = this.props; + let keys: string[] = []; + let eKeys: string[] = []; + const makeTreeNode = (index: Index, depth: number): DataNode => { + const title = Functions.mlang(index.title, lang) + (index.numOfItems > 0 ? ' (' + index.numOfItems + ')' : ''); + const children = IndexUtil.getChildren(index.id); + if (children.length === 0) { + return {key: String(index.id), title: title }; + } + const childTreeNodes = children.map((value: Index) => { + return makeTreeNode(value, depth + 1); + }); + if (depth < 1) { + eKeys.push(String(index.id)); + } + keys.push(String(index.id)); + return {key: String(index.id), title: title, children: childTreeNodes }; + }; + let elements: DataNode[] = []; + const index = IndexUtil.get(INDEX_ID_PUBLIC); + if (index !== null) { + elements.push(makeTreeNode(index, 0)); + } + return { + elements: elements, + keys: keys, + expandedKeys: eKeys, + } + } + + handleClickOpenAll() { + this.setState({ expandedKeys: this.state.expandableKeys }) + } + + handleClickCloseAll() { + this.setState({ expandedKeys: [] }) + } + + handleExpand(expandedKeys: (string|number)[], info: { + node: NodeInstance; + expanded: boolean; + nativeEvent: MouseEvent; + }): void { + const keys: string[] = expandedKeys.map((key) => { + return typeof key === 'string' ? key : String(key); + }); + this.setState({ expandedKeys: keys }); + } + + handleSelect(selectedKeys: (string|number)[], info: { + event: 'select'; + selected: boolean; + node: NodeInstance; + selectedNodes: DataNode[]; + nativeEvent: MouseEvent; + }): void { + const selectedKey = selectedKeys.shift() || 0; + const key = typeof selectedKey === 'string' ? parseInt(selectedKey, 10) : selectedKey; + const url = IndexUtil.getUrl(key); + this.props.history.push(url); + this.setState({ selectedKeys: [] }); + } + + render() { + return ( +
    + + + +
    + ); + } +} + +export default withRouter(IndexTree); diff --git a/src/database/blocks/Rankings.module.css b/src/database/blocks/Rankings.module.css new file mode 100644 index 0000000..362a532 --- /dev/null +++ b/src/database/blocks/Rankings.module.css @@ -0,0 +1,28 @@ +.heading { + margin: 0 0 3px; + font-size: 100%; + font-weight: normal; +} + +.item { + display: flex; + white-space: nowrap; + width: 100%; +} + +.order { + margin-right: 5px; +} + +.title { + overflow: hidden; + text-overflow: ellipsis; +} + +.count { + margin-left: 10px; +} + +.star { + margin-left: 5px; +} \ No newline at end of file diff --git a/src/database/blocks/Rankings.tsx b/src/database/blocks/Rankings.tsx new file mode 100644 index 0000000..bcaadfc --- /dev/null +++ b/src/database/blocks/Rankings.tsx @@ -0,0 +1,66 @@ +import React, { Fragment } from 'react'; +import { Link } from 'react-router-dom'; +import { MultiLang } from '../../config'; +import Functions from '../../functions'; +import imageStar from '../assets/images/star.gif'; +import rankings from '../assets/rankings.json'; +import ItemUtil, { ItemCore } from '../lib/ItemUtil'; +import styles from './Rankings.module.css'; + +interface Props { + lang: MultiLang; +} + +const orderLabel = (order: number, lang: string) => { + return String(order) + (lang === 'en' ? Functions.ordinal(order) : '位') +} + +const Rankings = (props: Props) => { + const items = [ + { + title: Functions.mlang('[en]Frequently accessed items[/en][ja]頻繁に閲覧されるアイテム[/ja]', props.lang), + list: rankings.accessed.map((item, idx) => { + const url = ItemUtil.getUrl(item as ItemCore); + const title = Functions.mlang(item.title, props.lang); + const order = orderLabel(idx + 1, props.lang); + return ( +
    +
    {order}
    +
    {title}
    + {idx === 0 &&
    {order}
    } +
    + ); + }), + }, + { + title: Functions.mlang('[en]Frequently downloaded items[/en][ja]頻繁にダウンロードされるアイテム[/ja]', props.lang), + list: rankings.downloaded.map((item, idx) => { + const url = ItemUtil.getUrl(item as ItemCore); + const title = Functions.mlang(item.title, props.lang); + const order = orderLabel(idx + 1, props.lang); + return ( +
    +
    {order}
    +
    {title}
    + {idx === 0 &&
    {order}
    } +
    + ); + }), + }, + ]; + return ( +
    + {items.map((item, idx) => { + return ( + + {idx !== 0 &&
    } +

    {item.title}

    +
    {item.list}
    +
    + ); + })} +
    + ); +} + +export default Rankings; \ No newline at end of file diff --git a/src/database/blocks/RecentContents.module.css b/src/database/blocks/RecentContents.module.css new file mode 100644 index 0000000..6466fb7 --- /dev/null +++ b/src/database/blocks/RecentContents.module.css @@ -0,0 +1,28 @@ +.heading { + margin: 0 0 3px; + font-size: 100%; + font-weight: normal; +} + +.item { + display: flex; + white-space: nowrap; + width: 100%; +} + +.order { + margin-right: 5px; +} + +.title { + overflow: hidden; + text-overflow: ellipsis; +} + +.date { + margin-left: 10px; +} + +.star { + margin-left: 5px; +} \ No newline at end of file diff --git a/src/database/blocks/RecentContents.tsx b/src/database/blocks/RecentContents.tsx new file mode 100644 index 0000000..166cddd --- /dev/null +++ b/src/database/blocks/RecentContents.tsx @@ -0,0 +1,39 @@ +import moment from 'moment'; +import React from 'react'; +import { Link } from 'react-router-dom'; +import { MultiLang } from '../../config'; +import Functions from '../../functions'; +import imageStar from '../assets/images/star.gif'; +import contents from '../assets/recent-contents.json'; +import ItemUtil, { ItemCore } from '../lib/ItemUtil'; +import styles from './RecentContents.module.css'; + +interface Props { + lang: MultiLang; +} + +const RecentContents = (props: Props) => { + const { lang } = props; + const list = contents.map((item, idx) => { + const url = ItemUtil.getUrl(item as ItemCore); + const title = Functions.mlang(item.title, lang); + const date = moment(new Date(item.last_update_date * 1000)).format('Y/M/D'); + const order = String(idx + 1) + (lang === 'en' ? Functions.ordinal(idx + 1) : '位'); + return ( +
    +
    {order}
    +
    {title}
    +
    ({date})
    + {idx === 0 &&
    {order}
    } +
    + ); + }); + return ( +
    +

    {Functions.mlang('[en]Newly Arrived Items[/en][ja]新着アイテム[/ja]', lang)}

    +
    {list}
    +
    + ); +} + +export default RecentContents; \ No newline at end of file diff --git a/src/database/blocks/Search.tsx b/src/database/blocks/Search.tsx new file mode 100644 index 0000000..3ea0738 --- /dev/null +++ b/src/database/blocks/Search.tsx @@ -0,0 +1,90 @@ +import React, { ChangeEvent, Component, FormEvent } from 'react'; +import { Link, RouteComponentProps, withRouter } from 'react-router-dom'; +import Config, { MultiLang } from '../../config'; +import Functions from '../../functions'; +import ItemUtil, { KeywordSearchType } from '../lib/ItemUtil'; + +interface Props extends RouteComponentProps { + lang: MultiLang; +} + +interface State { + type: KeywordSearchType; + keyword: string; + pathname: string; +} + +class Search extends Component { + + constructor(props: Props) { + super(props); + this.state = { + type: 'all', + keyword: '', + pathname: '', + }; + this.handleChangeType = this.handleChangeType.bind(this); + this.handleChangeKeyword = this.handleChangeKeyword.bind(this); + this.handleSubmit = this.handleSubmit.bind(this); + } + + static getDerivedStateFromProps(nextProps: Props, prevState: State) { + const pathname = nextProps.location.pathname; + if (pathname !== prevState.pathname) { + if (pathname === '/database/search') { + const { type, keyword } = ItemUtil.getSearchKeywordByQuery(nextProps.location.search); + return { type, keyword, pathname }; + } + return { + type: prevState.type, + keyword: prevState.keyword, + pathname + }; + } + return null; + } + + handleChangeKeyword(event: ChangeEvent) { + const keyword = event.target.value.trim(); + this.setState({ keyword }); + } + + handleChangeType(event: ChangeEvent) { + const type = event.target.value as KeywordSearchType; + this.setState({ type }); + } + + handleSubmit(event: FormEvent) { + event.preventDefault(); + const url = ItemUtil.getSearchByKeywordUrl(this.state.type, this.state.keyword); + this.props.history.push(url); + } + + render() { + const { lang } = this.props; + const options = [ + { value: 'all', label: '[en]All[/en][ja]全て[/ja]' }, + { value: 'basic', label: '[en]Title & Keyword[/en][ja]タイトル&キーワード[/ja]' }, + ]; + Config.XOONIPS_ITEMTYPES.forEach((type) => { + options.push({value: type, label: Functions.pascalCase(type)}) + }); + return ( +
    + +    + +
    + +      + {Functions.mlang('[en]Advanced[/en][ja]詳細検索[/ja]', lang)} +
    + ); + } +} + +export default withRouter(Search); \ No newline at end of file diff --git a/src/database/item-type/binder/BinderAdvancedSearch.tsx b/src/database/item-type/binder/BinderAdvancedSearch.tsx new file mode 100644 index 0000000..55c33b3 --- /dev/null +++ b/src/database/item-type/binder/BinderAdvancedSearch.tsx @@ -0,0 +1,26 @@ +import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase'; + +class BinderAdvancedSearch extends AdvancedSearchBase { + + constructor(props: AdvancedSearchBaseProps) { + super(props); + this.type = 'binder'; + this.title = 'Binder'; + this.state.values['title'] = ''; + this.state.values['keyword'] = ''; + this.state.values['description'] = ''; + this.state.values['doi'] = ''; + } + + getRows() { + const rows = [ + { label: '[en]Title[/en][ja]タイトル[/ja]', value: this.renderFieldInputText('title', 50) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: this.renderFieldInputText('keyword', 50) }, + { label: '[en]Description[/en][ja]概要[/ja]', value: this.renderFieldInputText('description', 50) }, + { label: 'ID', value: this.renderFieldInputText('doi', 50) }, + ]; + return rows; + } +} + +export default BinderAdvancedSearch; diff --git a/src/database/item-type/binder/BinderDetail.tsx b/src/database/item-type/binder/BinderDetail.tsx new file mode 100644 index 0000000..45b2158 --- /dev/null +++ b/src/database/item-type/binder/BinderDetail.tsx @@ -0,0 +1,95 @@ +import React, { Component } from 'react'; +import Functions from '../../../functions'; +import ItemUtil, { ItemBinder, Item } from '../../lib/ItemUtil'; +import DetailBase from '../lib/DetailBase'; +import ItemTypeField from '../lib/field'; +import { MultiLang } from '../../../config'; +import ItemType from '..'; + +interface Props { + lang: MultiLang; + item: ItemBinder; +} + +interface State { + items: Item[]; +} + +class BinderLinkItems extends Component { + constructor(props: Props) { + super(props); + this.state = { + items: [], + }; + } + + componentDidMount() { + this.updateItems(); + } + + componentDidUpdate(prevProps: Props, prevState: State) { + const prevItemIds = prevProps.item.item_link; + const nextItemIds = this.props.item.item_link; + if (prevItemIds.toString() !== nextItemIds.toString()) { + this.updateItems(); + } + } + + updateItems() { + const { item } = this.props; + const itemIds = item.item_link; + ItemUtil.getList(itemIds, (results) => { + const items = results.data; + this.setState({ items }); + }); + } + + render() { + const { lang } = this.props; + return ( + + + {this.state.items.map((item, idx) => { + const evenodd = idx % 2 ? 'even' : 'odd'; + return ; + })} + +
    + ); + } +} + +class BinderDetail extends DetailBase { + + getFields() { + const { lang } = this.props; + const item = this.props.item as ItemBinder; + return [ + { label: 'ID', value: item.doi }, + { label: '[en]Title[/en][ja]タイトル[/ja]', value: Functions.mlang(item.title, lang) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: }, + { label: '[en]Description[/en][ja]概要[/ja]', value: }, + { label: '[en]Last Modified Date[/en][ja]最終更新日[/ja]', value: }, + { label: '[en]Created Date[/en][ja]作成日[/ja]', value: }, + { label: '[en]Contributor[/en][ja]登録者[/ja]', value: }, + { label: '[en]Item Type[/en][ja]アイテムタイプ[/ja]', value: item.item_type_display_name }, + { label: '[en]Change Log(History)[/en][ja]変更履歴[/ja]', value: }, + { label: 'Index', value: }, + ]; + } + + render() { + const { lang } = this.props; + const item = this.props.item as ItemBinder; + const detail = super.render.call(this); + return ( + <> + {detail} +

    Registered Items

    + + + ); + } +} + +export default BinderDetail; \ No newline at end of file diff --git a/src/database/item-type/binder/BinderList.tsx b/src/database/item-type/binder/BinderList.tsx new file mode 100644 index 0000000..2393869 --- /dev/null +++ b/src/database/item-type/binder/BinderList.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import Functions from '../../../functions'; +import iconFile from '../../assets/images/icon_binder.gif'; +import { ItemBinder } from '../../lib/ItemUtil'; +import ListBase, { ListBaseProps } from '../lib/ListBase'; + +class BinderList extends ListBase { + + constructor(props: ListBaseProps) { + super(props); + this.label = 'Binder'; + this.icon = iconFile; + } + + renderBody() { + const { lang } = this.props; + const item = this.props.item as ItemBinder; + return ( + <> + {Functions.mlang(item.title, lang)}
    + {Functions.mlang(item.description, lang)} + + ); + } +} + +export default BinderList; diff --git a/src/database/item-type/binder/BinderTop.tsx b/src/database/item-type/binder/BinderTop.tsx new file mode 100644 index 0000000..cc714b7 --- /dev/null +++ b/src/database/item-type/binder/BinderTop.tsx @@ -0,0 +1,15 @@ +import TopBase, { TopBaseProps } from '../lib/TopBase'; +import iconFile from '../../assets/images/icon_binder.gif'; + +class BinderTop extends TopBase { + + constructor(props: TopBaseProps) { + super(props); + this.type = 'binder'; + this.label = 'Binder'; + this.icon = iconFile; + this.description = '[en]Binder collection.[/en][ja]バインダー[/ja]'; + } +} + +export default BinderTop; \ No newline at end of file diff --git a/src/database/item-type/binder/index.tsx b/src/database/item-type/binder/index.tsx new file mode 100644 index 0000000..3ae15c1 --- /dev/null +++ b/src/database/item-type/binder/index.tsx @@ -0,0 +1,13 @@ +import BinderAdvancedSearch from './BinderAdvancedSearch'; +import BinderDetail from './BinderDetail'; +import BinderList from './BinderList'; +import BinderTop from './BinderTop'; + +const ItemTypeBinder = { + Top: BinderTop, + List: BinderList, + Detail: BinderDetail, + AdvancedSearch: BinderAdvancedSearch, +}; + +export default ItemTypeBinder; diff --git a/src/database/item-type/book/BookAdvancedSearch.tsx b/src/database/item-type/book/BookAdvancedSearch.tsx new file mode 100644 index 0000000..b08534f --- /dev/null +++ b/src/database/item-type/book/BookAdvancedSearch.tsx @@ -0,0 +1,38 @@ +import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase'; + +class BookAdvancedSearch extends AdvancedSearchBase { + + constructor(props: AdvancedSearchBaseProps) { + super(props); + this.type = 'book'; + this.title = 'Book'; + this.state.values['title'] = ''; + this.state.values['keyword'] = ''; + this.state.values['description'] = ''; + this.state.values['doi'] = ''; + this.state.values['author'] = ''; + this.state.values['editor'] = ''; + this.state.values['publisher'] = ''; + this.state.values['publication_year'] = ''; + this.state.values['isbn'] = ''; + this.state.values['file.book_pdf.original_file_name'] = ''; + } + + getRows() { + const rows = [ + { label: '[en]Book Title[/en][ja]著書名[/ja]', value: this.renderFieldInputText('title', 50) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: this.renderFieldInputText('keyword', 50) }, + { label: '[en]Description[/en][ja]概要[/ja]', value: this.renderFieldInputText('description', 50) }, + { label: 'ID', value: this.renderFieldInputText('doi', 50) }, + { label: '[en]Author[/en][ja]著者[/ja]', value: this.renderFieldInputText('author', 50) }, + { label: '[en]Editor[/en][ja]編集者[/ja]', value: this.renderFieldInputText('editor', 50) }, + { label: '[en]Publisher[/en][ja]出版社[/ja]', value: this.renderFieldInputText('publisher', 50) }, + { label: '[en]Publication Year[/en][ja]出版年[/ja]', value: this.renderFieldInputText('publication_year', 10) }, + { label: 'ISBN', value: this.renderFieldInputText('isbn', 50) }, + { label: '[en]PDF File[/en][ja]PDF ファイル[/ja]', value: this.renderFieldInputText('file.book_pdf.original_file_name', 50) }, + ]; + return rows; + } +} + +export default BookAdvancedSearch; diff --git a/src/database/item-type/book/BookDetail.tsx b/src/database/item-type/book/BookDetail.tsx new file mode 100644 index 0000000..9099abe --- /dev/null +++ b/src/database/item-type/book/BookDetail.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import Functions from '../../../functions'; +import { ItemBook } from '../../lib/ItemUtil'; +import DetailBase from '../lib/DetailBase'; +import ItemTypeField from '../lib/field'; + +class BookDetail extends DetailBase { + + getFields() { + const { lang } = this.props; + const item = this.props.item as ItemBook; + return [ + { label: 'ID', value: item.doi }, + { label: '[en]Language[/en][ja]言語[/ja]', value: }, + { label: '[en]Book Title[/en][ja]著書名[/ja]', value: Functions.mlang(item.title, lang) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: }, + { label: '[en]Description[/en][ja]概要[/ja]', value: }, + { label: '[en]Last Modified Date[/en][ja]最終更新日[/ja]', value: }, + { label: '[en]Created Date[/en][ja]作成日[/ja]', value: }, + { label: '[en]Contributor[/en][ja]登録者[/ja]', value: }, + { label: '[en]Item Type[/en][ja]アイテムタイプ[/ja]', value: item.item_type_display_name }, + { label: '[en]Change Log(History)[/en][ja]変更履歴[/ja]', value: }, + { label: '[en]Author[/en][ja]著者[/ja]', value: }, + { label: '[en]Editor[/en][ja]編集者[/ja]', value: Functions.mlang(item.editor, lang) }, + { label: '[en]Publisher[/en][ja]出版社[/ja]', value: Functions.mlang(item.publisher, lang) }, + { label: '[en]Publication Year[/en][ja]出版年[/ja]', value: item.publication_year }, + { label: 'URL', value: {item.url} }, + { label: '[en]PDF File[/en][ja]PDF ファイル[/ja]', value: }, + { label: 'Index', value: }, + { label: '[en]Related to[/en][ja]関連アイテム[/ja]', value: }, + ]; + } +} + +export default BookDetail; diff --git a/src/database/item-type/book/BookList.tsx b/src/database/item-type/book/BookList.tsx new file mode 100644 index 0000000..9267be1 --- /dev/null +++ b/src/database/item-type/book/BookList.tsx @@ -0,0 +1,31 @@ +import React, { Fragment } from 'react'; +import { Link } from 'react-router-dom'; +import Functions from '../../../functions'; +import iconFile from '../../assets/images/icon_book.gif'; +import { ItemBook } from '../../lib/ItemUtil'; +import ListBase, { ListBaseProps } from '../lib/ListBase'; + +class BookList extends ListBase { + + constructor(props: ListBaseProps) { + super(props); + this.label = 'Book'; + this.icon = iconFile; + } + + renderBody() { + const { lang } = this.props; + const item = this.props.item as ItemBook; + const authors = item.author.map((author, i) => { + return {i > 0 && ', '}{Functions.mlang(author, lang)} + }); + return ( + <> + {Functions.mlang(item.title, lang)}
    + {authors} + + ); + } +} + +export default BookList; diff --git a/src/database/item-type/book/BookTop.tsx b/src/database/item-type/book/BookTop.tsx new file mode 100644 index 0000000..4fb2c35 --- /dev/null +++ b/src/database/item-type/book/BookTop.tsx @@ -0,0 +1,15 @@ +import TopBase, { TopBaseProps } from '../lib/TopBase'; +import iconFile from '../../assets/images/icon_book.gif'; + +class BookTop extends TopBase { + + constructor(props: TopBaseProps) { + super(props); + this.type = 'book'; + this.label = 'Book'; + this.icon = iconFile; + this.description = '[en]Related book collection.[/en][ja]関連書籍[/ja]'; + } +} + +export default BookTop; \ No newline at end of file diff --git a/src/database/item-type/book/index.tsx b/src/database/item-type/book/index.tsx new file mode 100644 index 0000000..3187d8b --- /dev/null +++ b/src/database/item-type/book/index.tsx @@ -0,0 +1,13 @@ +import BookTop from './BookTop'; +import BookList from './BookList'; +import BookDetail from './BookDetail'; +import BookAdvancedSearch from './BookAdvancedSearch'; + +const ItemTypeBook = { + Top: BookTop, + List: BookList, + Detail: BookDetail, + AdvancedSearch: BookAdvancedSearch, +}; + +export default ItemTypeBook; diff --git a/src/database/item-type/conference/ConferenceAdvancedSearch.tsx b/src/database/item-type/conference/ConferenceAdvancedSearch.tsx new file mode 100644 index 0000000..505835c --- /dev/null +++ b/src/database/item-type/conference/ConferenceAdvancedSearch.tsx @@ -0,0 +1,57 @@ +import React from 'react'; +import { ItemConferenceSubTypes } from '../../lib/ItemUtil'; +import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase'; + +class ConferenceAdvancedSearch extends AdvancedSearchBase { + + constructor(props: AdvancedSearchBaseProps) { + super(props); + this.type = 'conference'; + this.title = 'Conference'; + const now = new Date(); + const year = String(now.getFullYear()); + const month = String(now.getMonth() + 1); + const mday = String(now.getDate()); + this.state.values['title'] = ''; + this.state.values['presentation_type'] = ''; + this.state.values['author'] = ''; + this.state.values['conference_from_year'] = year; + this.state.values['conference_from_month'] = month; + this.state.values['conference_from_mday'] = mday; + this.state.values['conference_to_year'] = year; + this.state.values['conference_to_month'] = month; + this.state.values['conference_to_mday'] = mday; + this.setIgnoreKey('conference_from_year'); + this.setIgnoreKey('conference_from_month'); + this.setIgnoreKey('conference_from_mday'); + this.setIgnoreKey('conference_to_year'); + this.setIgnoreKey('conference_to_month'); + this.setIgnoreKey('conference_to_mday'); + } + + renderDate() { + return ( + <> +
    + {this.renderFieldDate('From', 'conference_from_year', 'conference_from_month', 'conference_from_mday')} + +
    +
    + {this.renderFieldDate('To', 'conference_to_year', 'conference_to_month', 'conference_to_mday')} +
    + + ); + } + + getRows() { + const rows = [ + { label: '[en]Presentation Title[/en][ja]発表議題[/ja]', value: this.renderFieldInputText('title', 50) }, + { label: '[en]Presentation Type[/en][ja]発表資料ファイル形式[/ja]', value: this.renderFieldSelect('presentation_type', ItemConferenceSubTypes) }, + { label: '[en]Author[/en][ja]発表者[/ja]', value: this.renderFieldInputText('author', 50) }, + { label: '[en]Date[/en][ja]日付[/ja]', value: this.renderDate() } + ]; + return rows; + } +} + +export default ConferenceAdvancedSearch; \ No newline at end of file diff --git a/src/database/item-type/conference/ConferenceDetail.tsx b/src/database/item-type/conference/ConferenceDetail.tsx new file mode 100644 index 0000000..6d2d6e3 --- /dev/null +++ b/src/database/item-type/conference/ConferenceDetail.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import Functions from '../../../functions'; +import { ItemConference } from '../../lib/ItemUtil'; +import DetailBase from '../lib/DetailBase'; +import ItemTypeField from '../lib/field'; +import ConferenceUtil from './ConferenceUtil'; + +class ConferenceDetail extends DetailBase { + + getFields() { + const { lang } = this.props; + const item = this.props.item as ItemConference; + return [ + { label: 'ID', value: item.doi }, + { label: '[en]Language[/en][ja]言語[/ja]', value: }, + { label: '[en]Conference Title[/en][ja]学会名[/ja]', value: Functions.mlang(item.conference_title, lang) }, + { label: '[en]Place[/en][ja]開催地[/ja]', value: item.place }, + { label: '[en]Date[/en][ja]日付[/ja]', value: }, + { label: '[en]Last Modified Date[/en][ja]最終更新日[/ja]', value: }, + { label: '[en]Created Date[/en][ja]作成日[/ja]', value: }, + { label: '[en]Contributor[/en][ja]登録者[/ja]', value: }, + { label: '[en]Item Type[/en][ja]アイテムタイプ[/ja]', value: item.item_type_display_name }, + { label: '[en]Change Log(History)[/en][ja]変更履歴[/ja]', value: }, + { label: '[en]Presentation Title[/en][ja]発表議題[/ja]', value: Functions.mlang(item.title, lang) }, + { label: '[en]Author[/en][ja]発表者[/ja]', value: }, + { label: '[en]Abstract[/en][ja]要約[/ja]', value: }, + { label: '[en]Presentation File[/en][ja]発表資料[/ja]', value: }, + { label: '[en]Presentation Type[/en][ja]発表資料ファイル形式[/ja]', value: }, + { label: '[en]Conference Paper[/en][ja]学会資料[/ja]', value: }, + { label: 'Index', value: }, + { label: '[en]Related to[/en][ja]関連アイテム[/ja]', value: }, + ]; + } +} + +export default ConferenceDetail; \ No newline at end of file diff --git a/src/database/item-type/conference/ConferenceList.tsx b/src/database/item-type/conference/ConferenceList.tsx new file mode 100644 index 0000000..b03298c --- /dev/null +++ b/src/database/item-type/conference/ConferenceList.tsx @@ -0,0 +1,33 @@ +import React, { Fragment } from 'react'; +import { Link } from 'react-router-dom'; +import { ItemConference } from '../../lib/ItemUtil'; +import ListBase, { ListBaseProps } from '../lib/ListBase'; +import ConferenceUtil from './ConferenceUtil'; +import iconFile from '../../assets/images/icon_conference.gif'; +import Functions from '../../../functions'; + +class ConferenceList extends ListBase { + + constructor(props: ListBaseProps) { + super(props); + this.label = 'Conference'; + this.icon = iconFile; + } + + renderBody() { + const { lang } = this.props; + const item = this.props.item as ItemConference; + const authors = item.author.map((author, i) => { + return {i > 0 && ', '}{Functions.mlang(author, lang)} + }); + return ( + <> + {Functions.mlang(item.title, lang)}
    + {Functions.mlang(item.conference_title, lang)} ()
    + {authors} + + ); + } +} + +export default ConferenceList; \ No newline at end of file diff --git a/src/database/item-type/conference/ConferenceTop.tsx b/src/database/item-type/conference/ConferenceTop.tsx new file mode 100644 index 0000000..885d9b7 --- /dev/null +++ b/src/database/item-type/conference/ConferenceTop.tsx @@ -0,0 +1,19 @@ +import { ItemConferenceSubTypes } from '../../lib/ItemUtil'; +import TopBase, { TopBaseProps } from '../lib/TopBase'; +import iconFile from '../../assets/images/icon_conference.gif'; + +class ConferenceTop extends TopBase { + + constructor(props: TopBaseProps) { + super(props); + this.type = 'conference'; + this.label = 'Conference'; + this.icon = iconFile; + // DBPF: + // this.description = '[en]Electrical presentation files for conference.[/en][ja]学会発表[/ja]'; + this.description = '[en]Presentations in conferences.[/en][ja]学術会議での発表[/ja]'; + this.subTypes = ItemConferenceSubTypes; + } +} + +export default ConferenceTop; \ No newline at end of file diff --git a/src/database/item-type/conference/ConferenceUtil.tsx b/src/database/item-type/conference/ConferenceUtil.tsx new file mode 100644 index 0000000..6cdbe2b --- /dev/null +++ b/src/database/item-type/conference/ConferenceUtil.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import { MultiLang } from '../../../config'; +import { ItemConference, ItemConferenceSubType, ItemConferenceSubTypes } from '../../lib/ItemUtil'; + +interface PresentationTypeProps { + lang: MultiLang; + type: ItemConferenceSubType; +} + +const PresentationType = (props: PresentationTypeProps) => { + const { type } = props; + const subtype = ItemConferenceSubTypes.find((value) => { return value.type === type; }); + if (typeof subtype === 'undefined') { + return null; + } + return ({subtype.label}); +} + +interface ConferenceDateProps { + lang: MultiLang; + item: ItemConference; +} + +const ConferenceDate = (props: ConferenceDateProps) => { + const { item } = props; + const monthStr = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + const from = 'From: ' + monthStr[item.conference_from_month - 1] + ' ' + item.conference_from_mday + ', ' + item.conference_from_year; + const to = 'To: ' + monthStr[item.conference_to_month - 1] + ' ' + item.conference_to_mday + ', ' + item.conference_to_year; + return ({from} {to}); +} + +const ConferenceUtil = { + PresentationType, + ConferenceDate, +} + +export default ConferenceUtil; \ No newline at end of file diff --git a/src/database/item-type/conference/index.tsx b/src/database/item-type/conference/index.tsx new file mode 100644 index 0000000..75272c4 --- /dev/null +++ b/src/database/item-type/conference/index.tsx @@ -0,0 +1,13 @@ +import ConferenceTop from './ConferenceTop'; +import ConferenceList from './ConferenceList'; +import ConferenceDetail from './ConferenceDetail'; +import ConferenceAdvancedSearch from './ConferenceAdvancedSearch'; + +const ItemTypeConference = { + Top: ConferenceTop, + List: ConferenceList, + Detail: ConferenceDetail, + AdvancedSearch: ConferenceAdvancedSearch, +}; + +export default ItemTypeConference; \ No newline at end of file diff --git a/src/database/item-type/data/DataAdvancedSearch.tsx b/src/database/item-type/data/DataAdvancedSearch.tsx new file mode 100644 index 0000000..e408d8b --- /dev/null +++ b/src/database/item-type/data/DataAdvancedSearch.tsx @@ -0,0 +1,46 @@ +import { ItemDataSubTypes } from '../../lib/ItemUtil'; +import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase'; + +class DataAdvancedSearch extends AdvancedSearchBase { + + constructor(props: AdvancedSearchBaseProps) { + super(props); + this.type = 'data'; + this.title = 'Data'; + const now = new Date(); + const year = String(now.getFullYear()); + const month = String(now.getMonth() + 1); + const mday = String(now.getDate()); + this.state.values['title'] = ''; + this.state.values['keyword'] = ''; + this.state.values['description'] = ''; + this.state.values['doi'] = ''; + this.state.values['data_type'] = ''; + this.state.values['experimenter'] = ''; + this.state.values['publication_year'] = year; + this.state.values['publication_month'] = month; + this.state.values['publication_mday'] = mday; + this.state.values['file.preview.caption'] = ''; + this.state.values['file.data_file.original_file_name'] = ''; + this.setIgnoreKey('publication_year'); + this.setIgnoreKey('publication_month'); + this.setIgnoreKey('publication_mday'); + } + + getRows() { + const rows = [ + { label: '[en]Title[/en][ja]タイトル[/ja]', value: this.renderFieldInputText('title', 50) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: this.renderFieldInputText('keyword', 50) }, + { label: '[en]Description[/en][ja]概要[/ja]', value: this.renderFieldInputText('description', 50) }, + { label: 'ID', value: this.renderFieldInputText('doi', 50) }, + { label: '[en]Data Type[/en][ja]データタイプ[/ja]', value: this.renderFieldSelect('data_type', ItemDataSubTypes) }, + { label: '[en]Experimenter[/en][ja]実験者[/ja]', value: this.renderFieldInputText('experimenter', 50) }, + { label: '[en]Date[/en][ja]日付[/ja]', value: this.renderFieldDate('', 'publication_year', 'publication_month', 'publication_mday') }, + { label: '[en]Caption[/en][ja]キャプション[/ja]', value: this.renderFieldInputText('file.preview.caption', 50) }, + { label: '[en]Data File[/en][ja]データファイル[/ja]', value: this.renderFieldInputText('file.data_file.original_file_name', 50) }, + ]; + return rows; + } +} + +export default DataAdvancedSearch; \ No newline at end of file diff --git a/src/database/item-type/data/DataDetail.tsx b/src/database/item-type/data/DataDetail.tsx new file mode 100644 index 0000000..bf3a024 --- /dev/null +++ b/src/database/item-type/data/DataDetail.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import Functions from '../../../functions'; +import ItemUtil, { ItemData } from '../../lib/ItemUtil'; +import DetailBase from '../lib/DetailBase'; +import ItemTypeField from '../lib/field'; +import SimPFLinkIcon from '../lib/field/SimPFLinkIcon'; +import DataUtil from './DataUtil'; + +class DataDetail extends DetailBase { + + getFields() { + const { lang } = this.props; + const item = this.props.item as ItemData; + const fields = [ + { label: 'ID', value: item.doi }, + { label: '[en]Language[/en][ja]言語[/ja]', value: }, + { label: '[en]Title[/en][ja]タイトル[/ja]', value: Functions.mlang(item.title, lang) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: }, + { label: '[en]Description[/en][ja]概要[/ja]', value: }, + { label: '[en]Date[/en][ja]日付[/ja]', value: }, + { label: '[en]Last Modified Date[/en][ja]最終更新日[/ja]', value: }, + { label: '[en]Created Date[/en][ja]作成日[/ja]', value: }, + { label: '[en]Contributor[/en][ja]登録者[/ja]', value: }, + { label: '[en]Item Type[/en][ja]アイテムタイプ[/ja]', value: item.item_type_display_name }, + { label: '[en]Change Log(History)[/en][ja]変更履歴[/ja]', value: }, + { label: '[en]Data Type[/en][ja]データタイプ[/ja]', value: }, + { label: '[en]Experimenter[/en][ja]実験者[/ja]', value: }, + { label: '[en]Preview[/en][ja]プレビュー[/ja]', value: }, + { label: '[en]Data File[/en][ja]データファイル[/ja]', value: }, + { label: 'Readme', value: }, + { label: 'Rights', value: }, + { label: 'Index', value: }, + { label: '[en]Related to[/en][ja]関連アイテム[/ja]', value: }, + ]; + const simpfLinkUrl = ItemUtil.getSimPFLinkUrl(item.item_id); + if (simpfLinkUrl !== '') { + const field = { label: 'Online Simulation', value: }; + fields.splice(14, 0, field); + } + return fields; + } +} + +export default DataDetail; \ No newline at end of file diff --git a/src/database/item-type/data/DataList.tsx b/src/database/item-type/data/DataList.tsx new file mode 100644 index 0000000..be78ce1 --- /dev/null +++ b/src/database/item-type/data/DataList.tsx @@ -0,0 +1,31 @@ +import React, { Fragment } from 'react'; +import { Link } from 'react-router-dom'; +import Functions from '../../../functions'; +import iconFile from '../../assets/images/icon_data.gif'; +import { ItemData } from '../../lib/ItemUtil'; +import ListBase, { ListBaseProps } from '../lib/ListBase'; + +class DataList extends ListBase { + + constructor(props: ListBaseProps) { + super(props); + this.label = 'Data'; + this.icon = iconFile; + } + + renderBody() { + const { lang } = this.props; + const item = this.props.item as ItemData; + const authors = item.experimenter.map((author, i) => { + return {i > 0 && ', '}{Functions.mlang(author, lang)} + }); + return ( + <> + {Functions.mlang(item.title, lang)}
    + {authors} + + ); + } +} + +export default DataList; \ No newline at end of file diff --git a/src/database/item-type/data/DataTop.tsx b/src/database/item-type/data/DataTop.tsx new file mode 100644 index 0000000..3054495 --- /dev/null +++ b/src/database/item-type/data/DataTop.tsx @@ -0,0 +1,19 @@ +import { ItemDataSubTypes } from '../../lib/ItemUtil'; +import TopBase, { TopBaseProps } from '../lib/TopBase'; +import iconFile from '../../assets/images/icon_data.gif'; + +class DataTop extends TopBase { + + constructor(props: TopBaseProps) { + super(props); + this.type = 'data'; + this.label = 'Data'; + this.icon = iconFile; + // DBPF: + // this.description = '[en]Result data in numerical text/image/movie formats.[/en][ja]実験結果の数値データ/画像/動画など[/ja]'; + this.description = '[en]Data from experiments or simulations.[/en][ja]実験やシミュレーションで得られたデータ[/ja]'; + this.subTypes = ItemDataSubTypes; + } +} + +export default DataTop; \ No newline at end of file diff --git a/src/database/item-type/data/DataUtil.tsx b/src/database/item-type/data/DataUtil.tsx new file mode 100644 index 0000000..9944054 --- /dev/null +++ b/src/database/item-type/data/DataUtil.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { MultiLang } from '../../../config'; +import { ItemDataSubType, ItemDataSubTypes } from '../../lib/ItemUtil'; + +interface DataTypeProps { + lang: MultiLang; + type: ItemDataSubType; +} + +const DataType = (props: DataTypeProps) => { + const { type } = props; + const subtype = ItemDataSubTypes.find((value) => { return value.type === type; }); + if (typeof subtype === 'undefined') { + return null; + } + return ({subtype.label}); +} + +const DataUtil = { + DataType, +} + +export default DataUtil; \ No newline at end of file diff --git a/src/database/item-type/data/index.tsx b/src/database/item-type/data/index.tsx new file mode 100644 index 0000000..21a88d8 --- /dev/null +++ b/src/database/item-type/data/index.tsx @@ -0,0 +1,13 @@ +import DataTop from './DataTop'; +import DataList from './DataList'; +import DataDetail from './DataDetail'; +import DataAdvancedSearch from './DataAdvancedSearch'; + +const ItemTypeData = { + Top: DataTop, + List: DataList, + Detail: DataDetail, + AdvancedSearch: DataAdvancedSearch, +}; + +export default ItemTypeData; \ No newline at end of file diff --git a/src/database/item-type/files/FilesAdvancedSearch.tsx b/src/database/item-type/files/FilesAdvancedSearch.tsx new file mode 100644 index 0000000..57b27d3 --- /dev/null +++ b/src/database/item-type/files/FilesAdvancedSearch.tsx @@ -0,0 +1,30 @@ +import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase'; + +class FilesAdvancedSearch extends AdvancedSearchBase { + + constructor(props: AdvancedSearchBaseProps) { + super(props); + this.type = 'files'; + this.title = 'Files'; + this.state.values['title'] = ''; + this.state.values['data_file_name'] = ''; + this.state.values['data_file_mimetype'] = ''; + this.state.values['data_file_filetype'] = ''; + this.state.values['keyword'] = ''; + this.state.values['description'] = ''; + } + + getRows() { + const rows = [ + { label: '[en]Title[/en][ja]タイトル[/ja]', value: this.renderFieldInputText('title', 50) }, + { label: '- [en]File Name[/en][ja]ファイル名[/ja]', value: this.renderFieldInputText('data_file_name', 50) }, + { label: '- [en]MIME Type[/en][ja]MIMEタイプ[/ja]', value: this.renderFieldInputText('data_file_mimetype', 50) }, + { label: '- [en]File Type[/en][ja]ファイルタイプ[/ja]', value: this.renderFieldInputText('data_file_filetype', 20) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: this.renderFieldInputText('keyword', 50) }, + { label: '[en]Description[/en][ja]概要[/ja]', value: this.renderFieldInputText('description', 50) }, + ]; + return rows; + } +} + +export default FilesAdvancedSearch; \ No newline at end of file diff --git a/src/database/item-type/files/FilesDetail.tsx b/src/database/item-type/files/FilesDetail.tsx new file mode 100644 index 0000000..89091d0 --- /dev/null +++ b/src/database/item-type/files/FilesDetail.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import Functions from '../../../functions'; +import { ItemFiles } from '../../lib/ItemUtil'; +import DetailBase from '../lib/DetailBase'; +import ItemTypeField from '../lib/field'; + +class FilesDetail extends DetailBase { + + getFields() { + const { lang } = this.props; + const item = this.props.item as ItemFiles; + return [ + { label: 'ID', value: item.doi }, + { label: '[en]Language[/en][ja]言語[/ja]', value: }, + { label: '[en]Title[/en][ja]タイトル[/ja]', value: Functions.mlang(item.title, lang) }, + { label: '[en]Last Modified Date[/en][ja]最終更新日[/ja]', value: }, + { label: '[en]Created Date[/en][ja]作成日[/ja]', value: }, + { label: '[en]Contributor[/en][ja]登録者[/ja]', value: }, + { label: '[en]Item Type[/en][ja]アイテムタイプ[/ja]', value: item.item_type_display_name }, + { label: '[en]Change Log(History)[/en][ja]変更履歴[/ja]', value: }, + { label: '[en]Data File[/en][ja]データファイル[/ja]', value: }, + { label: '- [en]File Name[/en][ja]ファイル名[/ja]', value: item.data_file_name }, + { label: '- [en]MIME Type[/en][ja]MIMEタイプ[/ja]', value: item.data_file_mimetype }, + { label: '- [en]File Type[/en][ja]ファイルタイプ[/ja]', value: item.data_file_filetype }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: }, + { label: '[en]Description[/en][ja]概要[/ja]', value: }, + { label: 'Index', value: }, + { label: '[en]Related to[/en][ja]関連アイテム[/ja]', value: }, + ]; + } +} + +export default FilesDetail; diff --git a/src/database/item-type/files/FilesList.tsx b/src/database/item-type/files/FilesList.tsx new file mode 100644 index 0000000..465237d --- /dev/null +++ b/src/database/item-type/files/FilesList.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import Functions from '../../../functions'; +import iconFile from '../../assets/images/icon_files.gif'; +import { ItemFiles } from '../../lib/ItemUtil'; +import Contributer from '../lib/field/Contributer'; +import ListBase, { ListBaseProps } from '../lib/ListBase'; + +class FilesList extends ListBase { + + constructor(props: ListBaseProps) { + super(props); + this.label = 'Files'; + this.icon = iconFile; + } + + renderBody() { + const { lang } = this.props; + const item = this.props.item as ItemFiles; + return ( + <> + {Functions.mlang(item.title, lang)}
    +
    + {item.data_file_mimetype} + + ); + } +} + +export default FilesList; \ No newline at end of file diff --git a/src/database/item-type/files/FilesTop.tsx b/src/database/item-type/files/FilesTop.tsx new file mode 100644 index 0000000..3e6fae9 --- /dev/null +++ b/src/database/item-type/files/FilesTop.tsx @@ -0,0 +1,17 @@ +import TopBase, { TopBaseProps } from '../lib/TopBase'; +import iconFile from '../../assets/images/icon_files.gif'; +import { ItemFilesSubTypes } from '../../lib/ItemUtil'; + +class FilesTop extends TopBase { + + constructor(props: TopBaseProps) { + super(props); + this.type = 'files'; + this.label = 'Files'; + this.icon = iconFile; + this.description = '[en]Various type of File.[/en][ja]ファイル[/ja]'; + this.subTypes = ItemFilesSubTypes; + } +} + +export default FilesTop; \ No newline at end of file diff --git a/src/database/item-type/files/FilesUtil.tsx b/src/database/item-type/files/FilesUtil.tsx new file mode 100644 index 0000000..0e10e42 --- /dev/null +++ b/src/database/item-type/files/FilesUtil.tsx @@ -0,0 +1,5 @@ + +const FilesUtil = { +} + +export default FilesUtil; \ No newline at end of file diff --git a/src/database/item-type/files/index.tsx b/src/database/item-type/files/index.tsx new file mode 100644 index 0000000..00ebdea --- /dev/null +++ b/src/database/item-type/files/index.tsx @@ -0,0 +1,13 @@ +import FilesTop from './FilesTop'; +import FilesList from './FilesList'; +import FilesDetail from './FilesDetail'; +import FilesAdvancedSearch from './FilesAdvancedSearch'; + +const ItemTypeFiles = { + Top: FilesTop, + List: FilesList, + Detail: FilesDetail, + AdvancedSearch: FilesAdvancedSearch, +}; + +export default ItemTypeFiles; \ No newline at end of file diff --git a/src/database/item-type/index.tsx b/src/database/item-type/index.tsx new file mode 100644 index 0000000..900cacc --- /dev/null +++ b/src/database/item-type/index.tsx @@ -0,0 +1,179 @@ +import React from 'react'; +import { MultiLang } from '../../config'; +import AdvancedSearchQuery from '../lib/AdvancedSearchQuery'; +import { Item, ItemBinder, ItemBook, ItemConference, ItemData, ItemFiles, ItemModel, ItemPaper, ItemPresentation, ItemSimulator, ItemStimulus, ItemTool, ItemUrl, ItemMemo } from '../lib/ItemUtil'; +import ItemTypeBinder from './binder'; +import ItemTypeBook from './book'; +import ItemTypeConference from './conference'; +import ItemTypeData from './data'; +import ItemTypeFiles from './files'; +import ItemTypeMemo from './memo'; +import ItemTypeModel from './model'; +import ItemTypePaper from './paper'; +import ItemTypePresentation from './presentation'; +import ItemTypeSimulator from './simulator'; +import ItemTypeStimulus from './stimulus'; +import ItemTypeTool from './tool'; +import ItemTypeUrl from './url'; + +interface TopProps { + lang: MultiLang; + type: string; +} +const Top = (props: TopProps) => { + const { lang, type } = props; + switch (type) { + case 'xnpbinder': + return ; + case 'xnpbook': + return ; + case 'xnpconference': + return ; + case 'xnpdata': + return ; + case 'xnpfiles': + return ; + case 'xnpmemo': + return ; + case 'xnpmodel': + return ; + case 'xnppaper': + return ; + case 'xnppresentation': + return ; + case 'xnpsimulator': + return ; + case 'xnpstimulus': + return ; + case 'xnptool': + return ; + case 'xnpurl': + return ; + default: + return null; + } +} + +interface ListProps { + lang: MultiLang; + item: Item; +} +const List = (props: ListProps) => { + const { lang, item } = props; + switch (item.item_type_name) { + case 'xnpbinder': + return ; + case 'xnpbook': + return ; + case 'xnpconference': + return ; + case 'xnpdata': + return ; + case 'xnpfiles': + return ; + case 'xnpmemo': + return ; + case 'xnpmodel': + return ; + case 'xnppaper': + return ; + case 'xnppresentation': + return ; + case 'xnpsimulator': + return ; + case 'xnpstimulus': + return ; + case 'xnptool': + return ; + case 'xnpurl': + return ; + default: + return null; + } +} + +interface DetailProps { + lang: MultiLang; + item: Item; +} +const Detail = (props: DetailProps) => { + const { lang, item } = props; + switch (item.item_type_name) { + case 'xnpbinder': + return ; + case 'xnpbook': + return ; + case 'xnpconference': + return ; + case 'xnpdata': + return ; + case 'xnpfiles': + return ; + case 'xnpmemo': + return ; + case 'xnpmodel': + return ; + case 'xnppaper': + return ; + case 'xnppresentation': + return ; + case 'xnpsimulator': + return ; + case 'xnpstimulus': + return ; + case 'xnptool': + return ; + case 'xnpurl': + return ; + default: + return null; + } +} + +interface AdvancedSearchProps { + lang: MultiLang; + type: string; + query: AdvancedSearchQuery; +} +const AdvancedSearch = (props: AdvancedSearchProps) => { + const { lang, type, query } = props; + switch (type) { + case 'xnpbinder': + return ; + case 'xnpbook': + return ; + case 'xnpconference': + return ; + case 'xnpdata': + return ; + case 'xnpfiles': + return ; + case 'xnpmemo': + return ; + case 'xnpmodel': + return ; + case 'xnppaper': + return ; + case 'xnppresentation': + return ; + case 'xnpsimulator': + return ; + case 'xnpstimulus': + return ; + case 'xnptool': + return ; + case 'xnpurl': + return ; + default: + return null; + } +} + +const ItemType = { + Top, + List, + Detail, + AdvancedSearch +} + +export default ItemType; \ No newline at end of file diff --git a/src/database/item-type/lib/AdvancedSearchBase.tsx b/src/database/item-type/lib/AdvancedSearchBase.tsx new file mode 100644 index 0000000..f1c5286 --- /dev/null +++ b/src/database/item-type/lib/AdvancedSearchBase.tsx @@ -0,0 +1,189 @@ +import React, { ChangeEvent, Component } from 'react'; +import { MultiLang } from '../../../config'; +import Functions from '../../../functions'; +import AdvancedSearchQuery from '../../lib/AdvancedSearchQuery'; +import { ItemSubTypes } from '../../lib/ItemUtil'; + +export interface AdvancedSearchBaseProps { + lang: MultiLang; + query: AdvancedSearchQuery; +} + +interface State { + show: boolean; + values: any; +} + +class AdvancedSearchBase extends Component { + + protected type: string = 'base' + protected title: string = 'Base'; + protected query: AdvancedSearchQuery; + protected ignoreKeys: string[] = []; + + constructor(props: AdvancedSearchBaseProps) { + super(props); + this.state = { + show: false, + values: {}, + } + this.query = props.query; + this.handleChangeTitleCheck = this.handleChangeTitleCheck.bind(this); + } + + updateQuery(key: string, value: string) { + if (this.ignoreKeys.includes(key)) { + this.query.delete(this.type, key); + } else { + this.query.set(this.type, key, value); + } + } + + setIgnoreKey(key: string) { + if (!this.ignoreKeys.includes(key)) { + this.ignoreKeys = this.ignoreKeys.concat(key); + } + this.query.delete(this.type, key); + } + + deleteIgnoreKey(key: string) { + if (this.ignoreKeys.includes(key)) { + this.ignoreKeys = this.ignoreKeys.filter((v) => { + return (v !== key); + }); + } + this.query.set(this.type, key, this.state.values[key]); + } + + updateField(key: string, value: string) { + let values = Object.assign({}, this.state.values); + values[key] = value; + this.updateQuery(key, value); + this.setState({ values }); + } + + handleChangeTitleCheck(e: ChangeEvent) { + const show = e.target.checked; + if (show) { + Object.keys(this.state.values).forEach((key) => { + const value = this.state.values[key]; + this.updateQuery(key, value); + }); + } else { + this.query.deleteType(this.type); + } + this.setState({ show }); + } + + getRows(): { label: string, value: JSX.Element }[] { + return []; + } + + renderFieldInputText(key: string, size: number) { + const onChange = (e: ChangeEvent) => { + this.updateField(key, e.target.value); + }; + return ( + + ); + } + + renderFieldSelect(key: string, values: ItemSubTypes) { + const onChange = (e: ChangeEvent) => { + this.updateField(key, e.target.value); + }; + const options = values.map(({ type, label }, i) => { + return ; + }); + return ( + + ); + } + + renderFieldDate(label: string, keyYear: string, keyMonth: string, keyMday: string) { + const onChange = (e: ChangeEvent) => { + if (e.target.checked) { + this.deleteIgnoreKey(keyYear); + keyMonth !== '' && this.deleteIgnoreKey(keyMonth); + keyMday !== '' && this.deleteIgnoreKey(keyMday); + } else { + this.setIgnoreKey(keyYear); + keyMonth !== '' && this.setIgnoreKey(keyMonth); + keyMday !== '' && this.setIgnoreKey(keyMday); + } + }; + const month = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + const monthOptions = month.map((value, i) => { + return ; + }) + let mdayOptions: JSX.Element[] = []; + for (let i = 1; i <= 31; i++) { + mdayOptions.push() + } + return ( +
    + + {label.length !== 0 && } + {keyMonth !== '' && + + } + {keyMday !== '' && + + } + this.updateField(keyYear, e.target.value)} /> +
    + ); + } + + renderBody() { + const { lang } = this.props; + if (this.state.show === false) { + return null; + } + const rows = this.getRows(); + const fields = rows.map((value, idx) => { + const evenodd = idx % 2 === 0 ? 'even' : 'odd'; + return ( + + {Functions.mlang(value.label, lang)} + {value.value} + + ); + }); + return ( + + + {fields} + +
    + ); + } + + render() { + return ( +
    + + + + + + +
    + + {this.title} +
    + {this.renderBody()} +
    + ); + } + +} + +export default AdvancedSearchBase; \ No newline at end of file diff --git a/src/database/item-type/lib/DetailBase.tsx b/src/database/item-type/lib/DetailBase.tsx new file mode 100644 index 0000000..3208d12 --- /dev/null +++ b/src/database/item-type/lib/DetailBase.tsx @@ -0,0 +1,43 @@ +import React, { Component, ReactNode } from 'react'; +import { MultiLang } from '../../../config'; +import Functions from '../../../functions'; +import { Item } from '../../lib/ItemUtil'; + +export interface DetailBaseField { + label: string; + value: ReactNode; +} + +export interface DetailBaseProps { + lang: MultiLang; + item: Item +} + +class DetailBase extends Component { + + getFields(): DetailBaseField[] { + return []; + } + + render() { + const { lang } = this.props; + const elements = this.getFields().map((value, idx) => { + const evenodd = idx % 2 === 0 ? 'even' : 'odd'; + return ( + + {Functions.mlang(value.label, lang)} + {value.value} + + ) + }); + return ( + + + {elements} + +
    + ); + } +} + +export default DetailBase; \ No newline at end of file diff --git a/src/database/item-type/lib/ListBase.tsx b/src/database/item-type/lib/ListBase.tsx new file mode 100644 index 0000000..435eb36 --- /dev/null +++ b/src/database/item-type/lib/ListBase.tsx @@ -0,0 +1,50 @@ +import React, { Component } from 'react'; +import { MultiLang } from '../../../config'; +import ItemUtil, { Item } from '../../lib/ItemUtil'; +import SimPFLinkIcon from './field/SimPFLinkIcon'; + +export interface ListBaseProps { + lang: MultiLang; + item: Item +}; + +class ListBase extends Component { + + protected label = ''; + protected icon = ''; + protected url: string; + protected simpfLinkUrl: string; + + constructor(props: ListBaseProps) { + super(props); + this.url = ItemUtil.getUrl(props.item); + this.simpfLinkUrl = ItemUtil.getSimPFLinkUrl(props.item.item_id); + } + + renderBody() { + return <>; + } + + render() { + const { lang } = this.props; + return ( + + + + + + + + +
    + {this.label} + + {this.renderBody()} + + +
    + ); + } +} + +export default ListBase; \ No newline at end of file diff --git a/src/database/item-type/lib/TopBase.tsx b/src/database/item-type/lib/TopBase.tsx new file mode 100644 index 0000000..a41f596 --- /dev/null +++ b/src/database/item-type/lib/TopBase.tsx @@ -0,0 +1,47 @@ +import React, { Component, Fragment } from 'react'; +import { Link } from 'react-router-dom'; +import { MultiLang } from '../../../config'; +import Functions from '../../../functions'; +import ItemUtil, { ItemSubTypes } from '../../lib/ItemUtil'; + +export interface TopBaseProps { + lang: MultiLang; +} + +class TopBase extends Component { + + protected type: string = ''; + protected label: string = ''; + protected icon: string = ''; + protected description: string = ''; + protected subTypes: ItemSubTypes = []; + + render() { + const { lang } = this.props; + const url = ItemUtil.getItemTypeSearchUrl(this.type); + const links = this.subTypes.map(({ type, label }, i) => { + return {i > 0 && ' / '}{label}; + }); + return ( +
    + + + + + + + +
    + {this.label} + + {this.label} +
    +
    +
    {Functions.mlang(this.description, lang)}
    + {links} +
    + ); + } +} + +export default TopBase; \ No newline at end of file diff --git a/src/database/item-type/lib/field/Author.tsx b/src/database/item-type/lib/field/Author.tsx new file mode 100644 index 0000000..9181ca8 --- /dev/null +++ b/src/database/item-type/lib/field/Author.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { MultiLang } from '../../../../config'; + +interface Props { + lang: MultiLang; + author: string[]; +} + +const Author = (props: Props) => { + const { author } = props; + if (author.length === 0) { + return null; + } + const elements = author.map((value, idx) => { + const evenodd = idx % 2 === 0 ? 'even' : 'odd'; + return {value}; + }); + return {elements}
    ; +} + +export default Author; \ No newline at end of file diff --git a/src/database/item-type/lib/field/ChangeLog.tsx b/src/database/item-type/lib/field/ChangeLog.tsx new file mode 100644 index 0000000..f3d9ba9 --- /dev/null +++ b/src/database/item-type/lib/field/ChangeLog.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { MultiLang } from '../../../../config'; +import Functions from '../../../../functions'; +import { ItemBasicChangeLog } from '../../../lib/ItemUtil'; +import DateTime from './DateTime'; + +interface Props { + lang: MultiLang; + changelog: ItemBasicChangeLog[]; +} + +const ChangeLog = (props: Props) => { + const { lang, changelog } = props; + if (changelog.length === 0) { + return null; + } + const elements = changelog.map((value, i) => { + return ( + + + {Functions.mlang(value.log, lang)} + + ); + }); + return ({elements}
    ); +} + +export default ChangeLog; \ No newline at end of file diff --git a/src/database/item-type/lib/field/Contributer.tsx b/src/database/item-type/lib/field/Contributer.tsx new file mode 100644 index 0000000..63261a9 --- /dev/null +++ b/src/database/item-type/lib/field/Contributer.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { MultiLang } from '../../../../config'; +import Functions from '../../../../functions'; + +interface Props { + lang: MultiLang; + uname: string; + name: string +} + +const Contributer = (props: Props) => { + const { lang, name, uname } = props; + const unsubscribed = '([en]Unsubscribed User[/en][ja]退会済みユーザ[/ja])'; + const label = uname === '' ? unsubscribed : (name === '' ? uname : name + ' (' + uname + ')'); + return {Functions.mlang(label, lang)}; +} + +export default Contributer; \ No newline at end of file diff --git a/src/database/item-type/lib/field/CreativeCommons.tsx b/src/database/item-type/lib/field/CreativeCommons.tsx new file mode 100644 index 0000000..b545f02 --- /dev/null +++ b/src/database/item-type/lib/field/CreativeCommons.tsx @@ -0,0 +1,56 @@ +import React from 'react'; +import { MultiLang } from '../../../../config'; + +export type CreativeCommonsType = 'by' | 'by-nc' | 'by-nc-nd' | 'by-nc-sa' | 'by-nd' | 'by-sa'; + +export const getCreativeCommonsType = (ccCommercialUse: number, ccModification: number): CreativeCommonsType => { + const cc = ccCommercialUse * 10 + ccModification; + switch (cc) { + case 0: + return 'by-nc-nd'; + case 1: + return 'by-nc-sa'; + case 2: + return 'by-nc'; + case 10: + return 'by-nd'; + case 11: + return 'by-sa'; + case 12: + default: + return 'by'; + } +} + +interface Props { + lang: MultiLang; + type: CreativeCommonsType; +} + +const CreativeCommons = (props: Props) => { + const { type } = props; + const url = 'http://creativecommons.org/licenses/' + type + '/4.0/'; + const logoUrl = 'https://i.creativecommons.org/l/' + type + '/4.0/88x31.png'; + const labels = { + by: 'Attribution', + nc: 'NonCommercial', + nd: 'NoDerivatives', + sa: 'ShareAlike', + } + const label = type.split('-').map((value) => { + const prop = value as 'by' | 'nc' | 'nd' | 'sa'; + return labels[prop]; + }).join('-'); + return ( + + + + + + + +
    Creative Commons LicenseThis work is licensed under a Criative Commons {label} 4.0 International License.
    + ); +} + +export default CreativeCommons; \ No newline at end of file diff --git a/src/database/item-type/lib/field/DateTime.tsx b/src/database/item-type/lib/field/DateTime.tsx new file mode 100644 index 0000000..0e9b1dc --- /dev/null +++ b/src/database/item-type/lib/field/DateTime.tsx @@ -0,0 +1,21 @@ +import moment from 'moment'; +import React from 'react'; +import { MultiLang } from '../../../../config'; + +interface Props { + lang: MultiLang; + date: number; + onlyDate?: boolean +} + +const DateTime = (props: Props) => { + const { date, onlyDate } = props; + const d = moment(new Date(date * 1000)); + let format = 'MMM D, Y'; + if (typeof onlyDate === 'undefined' || !onlyDate) { + format += ' HH:mm:ss'; + } + return {d.format(format)}; +} + +export default DateTime; diff --git a/src/database/item-type/lib/field/Description.tsx b/src/database/item-type/lib/field/Description.tsx new file mode 100644 index 0000000..353b3d9 --- /dev/null +++ b/src/database/item-type/lib/field/Description.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import XoopsCode from '../../../../common/lib/XoopsCode'; +import { MultiLang } from '../../../../config'; + +interface Props { + lang: MultiLang; + description: string; + className?: string; +} + +const Description = (props: Props) => { + const { lang, description, className } = props; + const textarea = ; + const name = typeof className === 'undefined' ? 'description' : className; + return (
    {textarea}
    ); +} + +export default Description; \ No newline at end of file diff --git a/src/database/item-type/lib/field/FileDownloadButton.module.css b/src/database/item-type/lib/field/FileDownloadButton.module.css new file mode 100644 index 0000000..dd40e7e --- /dev/null +++ b/src/database/item-type/lib/field/FileDownloadButton.module.css @@ -0,0 +1,21 @@ +.downloadButton { + display: inline-block; + padding: 7px 20px; + text-decoration: none !important; + font-weight: normal !important; + background: #f0f0f0; + color: #000 !important; + border: solid 1px #e0e0e0; + box-shadow: 2px 2px #bbbbbb; + border-radius: 5px; +} + +.downloadButton:hover { + background: #e8e8e8 !important; + border: solid 1px #cccccc; +} + +.downloadButton:active { + transform: translate(2px, 2px); + box-shadow: none; +} \ No newline at end of file diff --git a/src/database/item-type/lib/field/FileDownloadButton.tsx b/src/database/item-type/lib/field/FileDownloadButton.tsx new file mode 100644 index 0000000..968d441 --- /dev/null +++ b/src/database/item-type/lib/field/FileDownloadButton.tsx @@ -0,0 +1,55 @@ +import React, { Component } from 'react'; +import { MultiLang } from '../../../../config'; +import ItemUtil, { ItemBasicFile } from '../../../lib/ItemUtil'; +import styles from './FileDownloadButton.module.css'; +import LicenseAgreementDialog from './LicenseAgreementDialog'; + +interface Props { + lang: MultiLang; + file: ItemBasicFile; + rights: string; + useCc: number; + ccCommercialUse: number; + ccModification: number; +} + +interface State { + show: boolean; +} + +class FileDownloadButton extends Component { + + constructor(props: Props) { + super(props); + this.state = { + show: false, + }; + this.handleClickDownload = this.handleClickDownload.bind(this); + this.unsetShow = this.unsetShow.bind(this); + } + + handleClickDownload(e: React.MouseEvent) { + if (this.props.rights !== '') { + e.stopPropagation(); + e.preventDefault(); + this.setState({ show: true }); + } + } + + unsetShow() { + this.setState({ show: false }); + } + + render() { + const { lang, file, rights, useCc, ccCommercialUse, ccModification } = this.props; + const url = ItemUtil.getFileUrl(this.props.file); + return ( + <> + Download + + + ); + } +} + +export default FileDownloadButton; \ No newline at end of file diff --git a/src/database/item-type/lib/field/FileSize.tsx b/src/database/item-type/lib/field/FileSize.tsx new file mode 100644 index 0000000..0198e89 --- /dev/null +++ b/src/database/item-type/lib/field/FileSize.tsx @@ -0,0 +1,17 @@ +import React from 'react'; +import { MultiLang } from '../../../../config'; + +interface Props { + lang: MultiLang; + size: number; +} + +const FileSize = (props: Props) => { + const { size } = props; + const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; + const power = size > 0 ? Math.floor(Math.log(size) / Math.log(1024)) : 0; + const label = Math.round(size / Math.pow(1024, power) * 10) / 10 + ' ' + units[power] + return {label}; +} + +export default FileSize; \ No newline at end of file diff --git a/src/database/item-type/lib/field/FreeKeyword.tsx b/src/database/item-type/lib/field/FreeKeyword.tsx new file mode 100644 index 0000000..d33437e --- /dev/null +++ b/src/database/item-type/lib/field/FreeKeyword.tsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { MultiLang } from '../../../../config'; + +interface Props { + lang: MultiLang; + keyword: string[]; +} + +const FreeKeyword = (props: Props) => { + const { keyword } = props; + if (keyword.length === 0) { + return null; + } + const label = keyword.join(', '); + return ({label}); +} + +export default FreeKeyword; \ No newline at end of file diff --git a/src/database/item-type/lib/field/ItemFile.tsx b/src/database/item-type/lib/field/ItemFile.tsx new file mode 100644 index 0000000..12d52e1 --- /dev/null +++ b/src/database/item-type/lib/field/ItemFile.tsx @@ -0,0 +1,50 @@ +import React from 'react'; +import { MultiLang } from '../../../../config'; +import Functions from '../../../../functions'; +import { ItemBasicFile } from '../../../lib/ItemUtil'; +import DateTime from './DateTime'; +import FileDownloadButton from './FileDownloadButton'; +import FileSize from './FileSize'; + +interface Props { + lang: MultiLang; + file: ItemBasicFile[]; + type: string; + rights?: string; + useCc?: number; + ccCommercialUse?: number; + ccModification?: number; + downloadLimit?: number; +} + +const ItemFile = (props: Props) => { + const { lang, file, type } = props; + const rights = typeof props.rights === 'undefined' ? '' : props.rights; + const useCc = typeof props.useCc === 'undefined' ? 0 : props.useCc; + const ccCommercialUse = typeof props.ccCommercialUse === 'undefined' ? 0 : props.ccCommercialUse; + const ccModification = typeof props.ccModification === 'undefined' ? 0 : props.ccModification; + const downloadLimit = typeof props.downloadLimit === 'undefined' ? 0 : props.downloadLimit; + const data = file.find((value) => { + return value.file_type_name === type; + }); + if (typeof data === 'undefined') { + return null; + } + const date = new Date(data.timestamp); + const timestamp = Math.floor(date.valueOf() / 1000); + return ( +
    + {data.original_file_name}
    + + + + + + +
    Type: {data.mime_type}{downloadLimit === 0 && }
    Size:
    Last updated:
    + {downloadLimit === 1 && <>
    ({Functions.mlang('[en]File has been removed[/en][ja]ファイルは削除されました[/ja]', lang)})} +
    + ); +} + +export default ItemFile; \ No newline at end of file diff --git a/src/database/item-type/lib/field/ItemIndex.tsx b/src/database/item-type/lib/field/ItemIndex.tsx new file mode 100644 index 0000000..02937f6 --- /dev/null +++ b/src/database/item-type/lib/field/ItemIndex.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { MultiLang } from '../../../../config'; +import Functions from '../../../../functions'; +import IndexUtil from '../../../lib/IndexUtil'; +import { ItemBasicIndex } from '../../../lib/ItemUtil'; + +interface Props { + lang: MultiLang; + index: ItemBasicIndex[]; +} + +const ItemIndex = (props: Props) => { + const { lang, index } = props; + if (index.length === 0) { + return null; + } + const elements = index.map((value, idx) => { + const evenodd = idx % 2 === 0 ? 'even' : 'odd'; + const url = IndexUtil.getUrl(value.index_id); + return ({Functions.mlang(value.title, lang)}); + }); + return ({elements}
    ); +} + +export default ItemIndex; \ No newline at end of file diff --git a/src/database/item-type/lib/field/Language.tsx b/src/database/item-type/lib/field/Language.tsx new file mode 100644 index 0000000..4099c0b --- /dev/null +++ b/src/database/item-type/lib/field/Language.tsx @@ -0,0 +1,35 @@ +import React from 'react'; +import { ItemBasicLang } from '../../../lib/ItemUtil'; +import { MultiLang } from '../../../../config'; +import Functions from '../../../../functions'; + +interface Props { + lang: MultiLang; + itemLang: ItemBasicLang; +} + +const Language = (props: Props) => { + const { lang, itemLang } = props; + const langStr = { + eng: '[en]English[/en][ja]英語[/ja]', + jpn: '[en]Japanese[/en][ja]日本語[/ja]', + fra: '[en]French[/en][ja]フランス語[/ja]', + deu: '[en]German[/en][ja]ドイツ語[/ja]', + esl: '[en]Spanish[/en][ja]スペイン語[/ja]', + ita: '[en]Italian[/en][ja]イタリア語[/ja]', + dut: '[en]Dutch[/en][ja]オランダ語[/ja]', + sve: '[en]Swedish[/en][ja]スウェーデン語[/ja]', + nor: '[en]Norwegian[/en][ja]ノルウェー語[/ja]', + dan: '[en]Danish[/en][ja]デンマーク語[/ja]', + fin: '[en]Finnish[/en][ja]フィンランド語[/ja]', + por: '[en]Portuguese[/en][ja]ポルトガル語[/ja]', + chi: '[en]Chinese[/en][ja]中国語[/ja]', + kor: '[en]Korean[/en][ja]韓国語[/ja]', + } + if (!(itemLang in langStr)) { + return null; + } + return ({Functions.mlang(langStr[itemLang], lang)}); +} + +export default Language; \ No newline at end of file diff --git a/src/database/item-type/lib/field/LicenseAgreementDialog.module.css b/src/database/item-type/lib/field/LicenseAgreementDialog.module.css new file mode 100644 index 0000000..b2f4525 --- /dev/null +++ b/src/database/item-type/lib/field/LicenseAgreementDialog.module.css @@ -0,0 +1,38 @@ +.overlay { + position: fixed; + z-index: 90; + top: 0; + bottom: 0; + left: 0; + right: 0; + background-color: #000000; + opacity: 0.8; +} + +.dialog { + position: fixed; + background-color: #d8d8d8; + width: 570px; + z-index: 100; + top: 50%; + left: 50%; + right: auto; + bottom: auto; + margin: 0 auto; + padding: 20px; + transform: translate(-50%, -50%); + border-radius: 5px; +} + +.box { + background-color: #fff; + padding: 10px; +} + +.download { + text-align: center; +} + +.download button { + margin: 5px 5px 0; +} \ No newline at end of file diff --git a/src/database/item-type/lib/field/LicenseAgreementDialog.tsx b/src/database/item-type/lib/field/LicenseAgreementDialog.tsx new file mode 100644 index 0000000..3d065a6 --- /dev/null +++ b/src/database/item-type/lib/field/LicenseAgreementDialog.tsx @@ -0,0 +1,115 @@ +import React, { ChangeEvent, Component, MouseEvent } from 'react'; +import { Modal } from 'react-overlays'; +import { RouteComponentProps, withRouter } from 'react-router'; +import { MultiLang } from '../../../../config'; +import Functions from '../../../../functions'; +import ItemUtil, { ItemBasicFile } from '../../../lib/ItemUtil'; +import DateTime from './DateTime'; +import FileSize from './FileSize'; +import styles from './LicenseAgreementDialog.module.css'; +import Rights from './Rights'; + +interface Props extends RouteComponentProps { + lang: MultiLang; + file: ItemBasicFile; + rights: string; + useCc: number; + ccCommercialUse: number; + ccModification: number; + show: boolean; + unsetShow: () => void; +} + +interface State { + show: boolean; + disabled: boolean; +} + +class LicenseAgreementDialog extends Component { + + constructor(props: Props) { + super(props); + this.state = { + show: props.show, + disabled: false, + }; + this.handleChangeCheckbox = this.handleChangeCheckbox.bind(this); + this.handleClickDownload = this.handleClickDownload.bind(this); + this.handleClickCancel = this.handleClickCancel.bind(this); + } + + static getDerivedStateFromProps(nextProps: Props, prevState: State) { + if (nextProps.show && !prevState.show) { + return { disabled: true, show: nextProps.show }; + } + return null; + } + + handleChangeCheckbox(e: ChangeEvent) { + const disabled = e.target.value === '0'; + this.setState({ disabled }); + } + + handleClickDownload(e: MouseEvent) { + this.props.unsetShow(); + this.setState({ show: false }); + } + + handleClickCancel(e: MouseEvent) { + this.props.unsetShow(); + this.setState({ show: false }); + } + + renderBackdrop(props: any) { + return
    ; + } + + render() { + const { lang } = this.props; + const date = new Date(this.props.file.timestamp); + const timestamp = Math.floor(date.valueOf() / 1000); + const url = ItemUtil.getFileUrl(this.props.file); + return ( + +
    +
    + {Functions.mlang('[en]Download file information[/en][ja]ダウンロードするファイルの情報[/ja]', lang)} +
    + {this.props.file.original_file_name}
    + + + + + + +
    Type: {this.props.file.mime_type}
    Size:
    Last updated:
    +
    +
    +
    +
    + {Functions.mlang('[en]License agreement[/en][ja]ファイルのライセンス[/ja]', lang)} +
    + {Functions.mlang('[en]Please read the following license agreement carefully.[/en][ja]このファイルには下記のライセンスが設定されています。[/ja]', lang)} +
    + + {Functions.mlang('[en]I accept the terms in the license agreement.[/en][ja]ライセンスに同意します。[/ja]', lang)}
    + {Functions.mlang('[en]I do not accept the terms in the license agreement.[/en][ja]ライセンスに同意しません。[/ja]', lang)}
    +
    +
    +
    +
    +
    + Acceptance is needed to download this file. +
    + + + + +
    +
    +
    + ); + } +} + +export default withRouter(LicenseAgreementDialog); \ No newline at end of file diff --git a/src/database/item-type/lib/field/Preview.module.css b/src/database/item-type/lib/field/Preview.module.css new file mode 100644 index 0000000..7ce5431 --- /dev/null +++ b/src/database/item-type/lib/field/Preview.module.css @@ -0,0 +1,23 @@ +.previewBox { + text-align: center; + margin: 10px; +} + +.previewBox::after { + content: ""; + display: block; + clear: both; +} + +.preview { + width: 200px; + margin: 0 auto; + float: left; + text-align: center; +} + +.preview caption { + width: 200px; + margin: 5px; + font-size: 80%; +} \ No newline at end of file diff --git a/src/database/item-type/lib/field/Preview.tsx b/src/database/item-type/lib/field/Preview.tsx new file mode 100644 index 0000000..86ec5b3 --- /dev/null +++ b/src/database/item-type/lib/field/Preview.tsx @@ -0,0 +1,84 @@ +import React, { Component } from 'react'; +import Lightbox from 'react-image-lightbox'; +import 'react-image-lightbox/style.css'; +import { MultiLang } from '../../../../config'; +import Functions from '../../../../functions'; +import ItemUtil, { ItemBasicFile } from '../../../lib/ItemUtil'; +import styles from './Preview.module.css'; + +interface Props { + lang: MultiLang; + file: ItemBasicFile[]; +} + +interface State { + isOpen: boolean; + imageIndex: number; +} + +class Preview extends Component { + + constructor(props: Props) { + super(props); + this.state = { + isOpen: false, + imageIndex: 0, + }; + } + + render() { + const { lang, file } = this.props; + const data = file.filter((value) => { + return value.file_type_name === 'preview'; + }); + if (data.length === 0) { + return null; + } + let imageUrls: string[] = []; + const previews = data.map((value, idx) => { + const fileUrl = ItemUtil.getFileUrl(value); + const previewUrl = ItemUtil.getPreviewFileUrl(value); + const caption = Functions.mlang(value.caption, lang); + imageUrls.push(fileUrl); + return ( +
    + { + e.preventDefault(); + this.setState({ isOpen: true, imageIndex: idx }); + }}> + {caption} + +
    {caption}
    +
    + ); + }); + const { isOpen, imageIndex } = this.state; + return ( + <> +
    + {previews} +
    + {isOpen && + this.setState({ isOpen: false })} + onMovePrevRequest={() => + this.setState({ + imageIndex: (imageIndex + data.length - 1) % data.length, + }) + } + onMoveNextRequest={() => + this.setState({ + imageIndex: (imageIndex + 1) % data.length, + }) + } + /> + } + + ); + } +} + +export default Preview; \ No newline at end of file diff --git a/src/database/item-type/lib/field/PublicationDate.tsx b/src/database/item-type/lib/field/PublicationDate.tsx new file mode 100644 index 0000000..6da3a62 --- /dev/null +++ b/src/database/item-type/lib/field/PublicationDate.tsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { MultiLang } from '../../../../config'; +import DateTime from './DateTime'; + +interface Props { + lang: MultiLang; + year: number; + month: number; + mday: number; +} + +const PublicationDate = (props: Props) => { + const { lang, year, month, mday } = props; + const d = new Date(year + '-' + month + '-' + mday); + const timestamp = Math.floor(d.valueOf() / 1000); + return ; +} + +export default PublicationDate; \ No newline at end of file diff --git a/src/database/item-type/lib/field/Readme.tsx b/src/database/item-type/lib/field/Readme.tsx new file mode 100644 index 0000000..6fbd19b --- /dev/null +++ b/src/database/item-type/lib/field/Readme.tsx @@ -0,0 +1,15 @@ +import React from 'react'; +import { MultiLang } from '../../../../config'; +import Description from './Description'; + +interface Props { + lang: MultiLang; + readme: string; +} + +const Readme = (props: Props) => { + const { lang, readme } = props; + return ; +} + +export default Readme; \ No newline at end of file diff --git a/src/database/item-type/lib/field/RelatedTo.tsx b/src/database/item-type/lib/field/RelatedTo.tsx new file mode 100644 index 0000000..87cd518 --- /dev/null +++ b/src/database/item-type/lib/field/RelatedTo.tsx @@ -0,0 +1,74 @@ +import React, { Component } from 'react'; +import { MultiLang } from '../../../../config'; +import ItemType from '../../../item-type'; +import ItemUtil from '../../../lib/ItemUtil'; + +interface Props { + lang: MultiLang + relatedTo: number[]; +} + +interface State { + elements: JSX.Element[]; +} + +class RelatedTo extends Component { + + private isActive: boolean; + + constructor(props: Props) { + super(props); + this.state = { + elements: [], + }; + this.isActive = false; + } + + componentDidMount() { + this.isActive = true; + this.updateElements(this.props.relatedTo); + } + + componentDidUpdate(prevProps: Props) { + if (JSON.stringify(this.props.relatedTo) !== JSON.stringify(prevProps.relatedTo)) { + this.updateElements(this.props.relatedTo); + } + } + + componentWillUnmount() { + this.isActive = false; + } + + updateElements(relatedTo: number[]) { + const { lang } = this.props; + if (relatedTo.length === 0) { + this.setState({ elements: [] }); + } else { + ItemUtil.getList(relatedTo, (results) => { + const elements = results.data.map((item, idx) => { + const evenodd = idx % 0 ? 'even' : 'odd'; + return ; + }); + if (this.isActive) { + this.setState({ elements }); + } + }); + } + } + + render() { + if (this.state.elements.length === 0) { + return null; + } + return ( + + + + {this.state.elements} + +
    Item summary
    + ); + } +} + +export default RelatedTo; \ No newline at end of file diff --git a/src/database/item-type/lib/field/Rights.tsx b/src/database/item-type/lib/field/Rights.tsx new file mode 100644 index 0000000..25f65cf --- /dev/null +++ b/src/database/item-type/lib/field/Rights.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { MultiLang } from '../../../../config'; +import CreativeCommons, { getCreativeCommonsType } from './CreativeCommons'; +import Description from './Description'; + +interface Props { + lang: MultiLang; + rights: string; + useCc: number; + ccCommercialUse: number; + ccModification: number; +} + +const Rights = (props: Props) => { + const { lang, rights, useCc, ccCommercialUse, ccModification } = props; + if (useCc === 0) { + return ; + } + const ccType = getCreativeCommonsType(ccCommercialUse, ccModification); + return ; +} + +export default Rights; \ No newline at end of file diff --git a/src/database/item-type/lib/field/SimPFLinkIcon.tsx b/src/database/item-type/lib/field/SimPFLinkIcon.tsx new file mode 100644 index 0000000..1bfc8cb --- /dev/null +++ b/src/database/item-type/lib/field/SimPFLinkIcon.tsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { MultiLang } from '../../../../config'; +import imageButton from '../../../assets/images/simpf_button.png'; + +interface Props { + lang: MultiLang; + url: string; + isDetail: boolean; +} + +const SimPFLinkIcon = (props: Props) => { + const { url, isDetail } = props; + const title = 'Online Simulation'; + const size = isDetail ? 64 : 35; + if (url === '') { + return null; + } + return ( + + {title} + + );; +} + +export default SimPFLinkIcon; diff --git a/src/database/item-type/lib/field/index.tsx b/src/database/item-type/lib/field/index.tsx new file mode 100644 index 0000000..12e70e6 --- /dev/null +++ b/src/database/item-type/lib/field/index.tsx @@ -0,0 +1,39 @@ +import Author from './Author'; +import ChangeLog from './ChangeLog'; +import Contributer from './Contributer'; +import CreativeCommons from './CreativeCommons'; +import DateTime from './DateTime'; +import Description from './Description'; +import FileSize from './FileSize'; +import FileDownloadButton from './FileDownloadButton'; +import FreeKeyword from './FreeKeyword'; +import ItemFile from './ItemFile'; +import ItemIndex from './ItemIndex'; +import Language from './Language'; +import Preview from './Preview'; +import PublicationDate from './PublicationDate'; +import Readme from './Readme'; +import RelatedTo from './RelatedTo'; +import Rights from './Rights'; + +const ItemTypeField = { + Author, + ChangeLog, + Contributer, + CreativeCommons, + DateTime, + Description, + FileDownloadButton, + FileSize, + FreeKeyword, + ItemFile, + ItemIndex, + Language, + Preview, + PublicationDate, + Readme, + RelatedTo, + Rights, +}; + +export default ItemTypeField; \ No newline at end of file diff --git a/src/database/item-type/memo/MemoAdvancedSearch.tsx b/src/database/item-type/memo/MemoAdvancedSearch.tsx new file mode 100644 index 0000000..9438658 --- /dev/null +++ b/src/database/item-type/memo/MemoAdvancedSearch.tsx @@ -0,0 +1,28 @@ +import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase'; + +class MemoAdvancedSearch extends AdvancedSearchBase { + + constructor(props: AdvancedSearchBaseProps) { + super(props); + this.type = 'memo'; + this.title = 'Memo'; + this.state.values['title'] = ''; + this.state.values['keyword'] = ''; + this.state.values['description'] = ''; + this.state.values['doi'] = ''; + this.state.values['item_link'] = ''; + } + + getRows() { + const rows = [ + { label: '[en]Title[/en][ja]タイトル[/ja]', value: this.renderFieldInputText('title', 50) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: this.renderFieldInputText('keyword', 50) }, + { label: '[en]Description[/en][ja]概要[/ja]', value: this.renderFieldInputText('description', 50) }, + { label: 'ID', value: this.renderFieldInputText('doi', 50) }, + { label: '[en]Item Link[/en][ja]リンク[/ja]', value: this.renderFieldInputText('item_link', 50) }, + ]; + return rows; + } +} + +export default MemoAdvancedSearch; diff --git a/src/database/item-type/memo/MemoDetail.tsx b/src/database/item-type/memo/MemoDetail.tsx new file mode 100644 index 0000000..100441d --- /dev/null +++ b/src/database/item-type/memo/MemoDetail.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import XoopsCode from '../../../common/lib/XoopsCode'; +import Functions from '../../../functions'; +import { ItemMemo } from '../../lib/ItemUtil'; +import DetailBase from '../lib/DetailBase'; +import ItemTypeField from '../lib/field'; + +class MemoDetail extends DetailBase { + + getFields() { + const { lang } = this.props; + const item = this.props.item as ItemMemo; + const fields = [ + { label: 'ID', value: item.doi }, + { label: '[en]Language[/en][ja]言語[/ja]', value: }, + { label: '[en]Title[/en][ja]タイトル[/ja]', value: Functions.mlang(item.title, lang) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: }, + { label: '[en]Description[/en][ja]概要[/ja]', value: }, + { label: '[en]Last Modified Date[/en][ja]最終更新日[/ja]', value: }, + { label: '[en]Created Date[/en][ja]作成日[/ja]', value: }, + { label: '[en]Contributor[/en][ja]登録者[/ja]', value: }, + { label: '[en]Item Type[/en][ja]アイテムタイプ[/ja]', value: item.item_type_display_name }, + { label: '[en]Change Log(History)[/en][ja]変更履歴[/ja]', value: }, + { label: '[en]Item Link[/en][ja]リンク[/ja]', value: }, + { label: '[en]Memo File[/en][ja]メモファイル[/ja]', value: }, + { label: 'Index', value: }, + { label: '[en]Related to[/en][ja]関連アイテム[/ja]', value: }, + ]; + return fields; + } +} + +export default MemoDetail; diff --git a/src/database/item-type/memo/MemoList.tsx b/src/database/item-type/memo/MemoList.tsx new file mode 100644 index 0000000..1fbd2cd --- /dev/null +++ b/src/database/item-type/memo/MemoList.tsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import XoopsCode from '../../../common/lib/XoopsCode'; +import Functions from '../../../functions'; +import iconFile from '../../assets/images/icon_memo.gif'; +import { ItemMemo } from '../../lib/ItemUtil'; +import ListBase, { ListBaseProps } from '../lib/ListBase'; + +class MemoList extends ListBase { + + constructor(props: ListBaseProps) { + super(props); + this.label = 'Memo'; + this.icon = iconFile; + } + + renderBody() { + const { lang } = this.props; + const item = this.props.item as ItemMemo; + const link = item.item_link !== '' ? : null; + return ( + <> + {Functions.mlang(item.title, lang)}
    + {link} + + ); + } +} + +export default MemoList; diff --git a/src/database/item-type/memo/MemoTop.tsx b/src/database/item-type/memo/MemoTop.tsx new file mode 100644 index 0000000..8245f96 --- /dev/null +++ b/src/database/item-type/memo/MemoTop.tsx @@ -0,0 +1,15 @@ +import TopBase, { TopBaseProps } from '../lib/TopBase'; +import iconFile from '../../assets/images/icon_memo.gif'; + +class MemoTop extends TopBase { + + constructor(props: TopBaseProps) { + super(props); + this.type = 'memo'; + this.label = 'Memo'; + this.icon = iconFile; + this.description = '[en]Personal Memo Pad.[/en][ja]汎用メモパッド[/ja]'; + } +} + +export default MemoTop; diff --git a/src/database/item-type/memo/index.tsx b/src/database/item-type/memo/index.tsx new file mode 100644 index 0000000..d5d2951 --- /dev/null +++ b/src/database/item-type/memo/index.tsx @@ -0,0 +1,13 @@ +import MemoTop from './MemoTop'; +import MemoList from './MemoList'; +import MemoDetail from './MemoDetail'; +import MemoAdvancedSearch from './MemoAdvancedSearch'; + +const ItemTypeMemo = { + Top: MemoTop, + List: MemoList, + Detail: MemoDetail, + AdvancedSearch: MemoAdvancedSearch, +}; + +export default ItemTypeMemo; \ No newline at end of file diff --git a/src/database/item-type/model/ModelAdvancedSearch.tsx b/src/database/item-type/model/ModelAdvancedSearch.tsx new file mode 100644 index 0000000..02cfd40 --- /dev/null +++ b/src/database/item-type/model/ModelAdvancedSearch.tsx @@ -0,0 +1,35 @@ +import { ItemModelSubTypes } from '../../lib/ItemUtil'; +import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase'; + +class ModelAdvancedSearch extends AdvancedSearchBase { + + constructor(props: AdvancedSearchBaseProps) { + super(props); + this.type = 'model'; + this.title = 'Model'; + this.state.values['title'] = ''; + this.state.values['keyword'] = ''; + this.state.values['description'] = ''; + this.state.values['doi'] = ''; + this.state.values['model_type'] = ''; + this.state.values['creator'] = ''; + this.state.values['file.preview.caption'] = ''; + this.state.values['file.model_data.original_file_name'] = ''; + } + + getRows() { + const rows = [ + { label: '[en]Title[/en][ja]タイトル[/ja]', value: this.renderFieldInputText('title', 50) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: this.renderFieldInputText('keyword', 50) }, + { label: '[en]Description[/en][ja]概要[/ja]', value: this.renderFieldInputText('description', 50) }, + { label: 'ID', value: this.renderFieldInputText('doi', 50) }, + { label: '[en]Model Type[/en][ja]モデルタイプ[/ja]', value: this.renderFieldSelect('model_type', ItemModelSubTypes) }, + { label: '[en]Creator[/en][ja]作成者[/ja]', value: this.renderFieldInputText('creator', 50) }, + { label: '[en]Caption[/en][ja]キャプション[/ja]', value: this.renderFieldInputText('file.preview.caption', 50) }, + { label: '[en]Model File[/en][ja]モデルファイル[/ja]', value: this.renderFieldInputText('file.model_data.original_file_name', 50) }, + ]; + return rows; + } +} + +export default ModelAdvancedSearch; \ No newline at end of file diff --git a/src/database/item-type/model/ModelDetail.tsx b/src/database/item-type/model/ModelDetail.tsx new file mode 100644 index 0000000..837b712 --- /dev/null +++ b/src/database/item-type/model/ModelDetail.tsx @@ -0,0 +1,43 @@ +import React from 'react'; +import Functions from '../../../functions'; +import ItemUtil, { ItemModel } from '../../lib/ItemUtil'; +import DetailBase from '../lib/DetailBase'; +import ItemTypeField from '../lib/field'; +import SimPFLinkIcon from '../lib/field/SimPFLinkIcon'; +import ModelUtil from './ModelUtil'; + +class ModelDetail extends DetailBase { + + getFields() { + const { lang } = this.props; + const item = this.props.item as ItemModel; + const fields = [ + { label: 'ID', value: item.doi }, + { label: '[en]Language[/en][ja]言語[/ja]', value: }, + { label: '[en]Title[/en][ja]タイトル[/ja]', value: Functions.mlang(item.title, lang) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: }, + { label: '[en]Description[/en][ja]概要[/ja]', value: }, + { label: '[en]Last Modified Date[/en][ja]最終更新日[/ja]', value: }, + { label: '[en]Created Date[/en][ja]作成日[/ja]', value: }, + { label: '[en]Contributor[/en][ja]登録者[/ja]', value: }, + { label: '[en]Item Type[/en][ja]アイテムタイプ[/ja]', value: item.item_type_display_name }, + { label: '[en]Change Log(History)[/en][ja]変更履歴[/ja]', value: }, + { label: '[en]Model Type[/en][ja]モデルタイプ[/ja]', value: }, + { label: '[en]Creator[/en][ja]作成者[/ja]', value: }, + { label: '[en]Preview[/en][ja]プレビュー[/ja]', value: }, + { label: '[en]Model File[/en][ja]モデルファイル[/ja]', value: }, + { label: 'Readme', value: }, + { label: 'Rights', value: }, + { label: 'Index', value: }, + { label: '[en]Related to[/en][ja]関連アイテム[/ja]', value: }, + ]; + const simpfLinkUrl = ItemUtil.getSimPFLinkUrl(item.item_id); + if (simpfLinkUrl !== '') { + const field = { label: 'Online Simulation', value: }; + fields.splice(13, 0, field); + } + return fields; + } +} + +export default ModelDetail; \ No newline at end of file diff --git a/src/database/item-type/model/ModelList.tsx b/src/database/item-type/model/ModelList.tsx new file mode 100644 index 0000000..b709fa2 --- /dev/null +++ b/src/database/item-type/model/ModelList.tsx @@ -0,0 +1,31 @@ +import React, { Fragment } from 'react'; +import { Link } from 'react-router-dom'; +import Functions from '../../../functions'; +import iconFile from '../../assets/images/icon_model.gif'; +import { ItemModel } from '../../lib/ItemUtil'; +import ListBase, { ListBaseProps } from '../lib/ListBase'; + +class ModelList extends ListBase { + + constructor(props: ListBaseProps) { + super(props); + this.label = 'Model'; + this.icon = iconFile; + } + + renderBody() { + const { lang } = this.props; + const item = this.props.item as ItemModel; + const authors = item.creator.map((author, i) => { + return {i > 0 && ', '}{Functions.mlang(author, lang)} + }); + return ( + <> + {Functions.mlang(item.title, lang)}
    + {authors} + + ); + } +} + +export default ModelList; \ No newline at end of file diff --git a/src/database/item-type/model/ModelTop.tsx b/src/database/item-type/model/ModelTop.tsx new file mode 100644 index 0000000..e5431f2 --- /dev/null +++ b/src/database/item-type/model/ModelTop.tsx @@ -0,0 +1,19 @@ +import { ItemModelSubTypes } from '../../lib/ItemUtil'; +import TopBase, { TopBaseProps } from '../lib/TopBase'; +import iconFile from '../../assets/images/icon_model.gif'; + +class ModelTop extends TopBase { + + constructor(props: TopBaseProps) { + super(props); + this.type = 'model'; + this.label = 'Model'; + this.icon = iconFile; + // DBPF: + //this.description = '[en]Model programs/scripts.[/en][ja]モデル プログラム/スクリプト[/ja]'; + this.description = '[en]Descriptions of models[/en][ja]モデルの記述[/ja]'; + this.subTypes = ItemModelSubTypes; + } +} + +export default ModelTop; \ No newline at end of file diff --git a/src/database/item-type/model/ModelUtil.tsx b/src/database/item-type/model/ModelUtil.tsx new file mode 100644 index 0000000..43a0c89 --- /dev/null +++ b/src/database/item-type/model/ModelUtil.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { MultiLang } from '../../../config'; +import { ItemModelSubType, ItemModelSubTypes } from '../../lib/ItemUtil'; + +interface ModelTypeProps { + lang: MultiLang; + type: ItemModelSubType; +} + +const ModelType = (props: ModelTypeProps) => { + const { type } = props; + const subtype = ItemModelSubTypes.find((value) => { return value.type === type; }); + if (typeof subtype === 'undefined') { + return null; + } + return ({subtype.label}); +} + +const ModelUtil = { + ModelType, +} + +export default ModelUtil; \ No newline at end of file diff --git a/src/database/item-type/model/index.tsx b/src/database/item-type/model/index.tsx new file mode 100644 index 0000000..dba8611 --- /dev/null +++ b/src/database/item-type/model/index.tsx @@ -0,0 +1,13 @@ +import ModelTop from './ModelTop'; +import ModelList from './ModelList'; +import ModelDetail from './ModelDetail'; +import ModelAdvancedSearch from './ModelAdvancedSearch'; + +const ItemTypeModel = { + Top: ModelTop, + List: ModelList, + Detail: ModelDetail, + AdvancedSearch: ModelAdvancedSearch, +}; + +export default ItemTypeModel; \ No newline at end of file diff --git a/src/database/item-type/paper/PaperAdvancedSearch.tsx b/src/database/item-type/paper/PaperAdvancedSearch.tsx new file mode 100644 index 0000000..a74e2d4 --- /dev/null +++ b/src/database/item-type/paper/PaperAdvancedSearch.tsx @@ -0,0 +1,39 @@ +import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase'; + +class PaperAdvancedSearch extends AdvancedSearchBase { + constructor(props: AdvancedSearchBaseProps) { + super(props); + this.type = 'paper'; + this.title = 'Paper'; + this.state.values['pubmed_id'] = ''; + this.state.values['title'] = ''; + this.state.values['keyword'] = ''; + this.state.values['description'] = ''; + this.state.values['doi'] = ''; + this.state.values['author'] = ''; + this.state.values['journal'] = ''; + this.state.values['publication_year'] = ''; + this.state.values['volume'] = ''; + this.state.values['number'] = ''; + this.state.values['page'] = ''; + } + + getRows() { + const rows = [ + { label: 'PubMed ID', value: this.renderFieldInputText('pubmed_id', 50) }, + { label: '[en]Title[/en][ja]タイトル[/ja]', value: this.renderFieldInputText('title', 50) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: this.renderFieldInputText('keyword', 50) }, + { label: '[en]Description[/en][ja]概要[/ja]', value: this.renderFieldInputText('description', 50) }, + { label: 'ID', value: this.renderFieldInputText('doi', 50) }, + { label: '[en]Author[/en][ja]著者[/ja]', value: this.renderFieldInputText('author', 50) }, + { label: '[en]Journal[/en][ja]ジャーナル[/ja]', value: this.renderFieldInputText('journal', 50) }, + { label: '[en]Publication Year[/en][ja]出版年[/ja]', value: this.renderFieldInputText('publication_year', 10) }, + { label: '[en]Volume[/en][ja]巻[/ja]', value: this.renderFieldInputText('volume', 50) }, + { label: '[en]Number[/en][ja]号[/ja]', value: this.renderFieldInputText('number', 50) }, + { label: '[en]Page[/en][ja]ページ[/ja]', value: this.renderFieldInputText('page', 50) }, + ]; + return rows; + } +} + +export default PaperAdvancedSearch; \ No newline at end of file diff --git a/src/database/item-type/paper/PaperDetail.tsx b/src/database/item-type/paper/PaperDetail.tsx new file mode 100644 index 0000000..5884fbe --- /dev/null +++ b/src/database/item-type/paper/PaperDetail.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import Functions from '../../../functions'; +import { ItemPaper } from '../../lib/ItemUtil'; +import DetailBase from '../lib/DetailBase'; +import ItemTypeField from '../lib/field'; +import PaperUtil from './PaperUtil'; + +class PaperDetail extends DetailBase { + + getFields() { + const { lang } = this.props; + const item = this.props.item as ItemPaper; + return [ + { label: 'ID', value: item.doi }, + { label: '[en]Language[/en][ja]言語[/ja]', value: }, + { label: 'PubMed ID', value: }, + { label: '[en]Title[/en][ja]タイトル[/ja]', value: Functions.mlang(item.title, lang) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: }, + { label: '[en]Description[/en][ja]概要[/ja]', value: }, + { label: '[en]Last Modified Date[/en][ja]最終更新日[/ja]', value: }, + { label: '[en]Created Date[/en][ja]作成日[/ja]', value: }, + { label: '[en]Contributor[/en][ja]登録者[/ja]', value: }, + { label: '[en]Item Type[/en][ja]アイテムタイプ[/ja]', value: item.item_type_display_name }, + { label: '[en]Change Log(History)[/en][ja]変更履歴[/ja]', value: }, + { label: '[en]Author[/en][ja]著者[/ja]', value: }, + { label: '[en]Journal[/en][ja]ジャーナル[/ja]', value: Functions.mlang(item.journal, lang) }, + { label: '[en]Publication Year[/en][ja]出版年[/ja]', value: item.publication_year }, + { label: '[en]Volume[/en][ja]巻[/ja]', value: item.volume }, + { label: '[en]Number[/en][ja]号[/ja]', value: item.number }, + { label: '[en]Page[/en][ja]ページ[/ja]', value: item.page }, + { label: 'Index', value: }, + { label: '[en]Related to[/en][ja]関連アイテム[/ja]', value: }, + ]; + } +} + +export default PaperDetail; \ No newline at end of file diff --git a/src/database/item-type/paper/PaperList.tsx b/src/database/item-type/paper/PaperList.tsx new file mode 100644 index 0000000..673d6d3 --- /dev/null +++ b/src/database/item-type/paper/PaperList.tsx @@ -0,0 +1,38 @@ +import React, { Fragment } from 'react'; +import { Link } from 'react-router-dom'; +import Functions from '../../../functions'; +import iconFile from '../../assets/images/icon_paper.gif'; +import { ItemPaper } from '../../lib/ItemUtil'; +import ListBase, { ListBaseProps } from '../lib/ListBase'; +import PaperUtil from './PaperUtil'; + +class PaperList extends ListBase { + + constructor(props: ListBaseProps) { + super(props); + this.label = 'Paper'; + this.icon = iconFile; + } + + renderBody() { + const { lang } = this.props; + const item = this.props.item as ItemPaper; + const authors = item.author.map((author, i) => { + return {i > 0 && ', '}{Functions.mlang(author, lang)} + }); + return ( + <> + {Functions.mlang(item.title, lang)}
    + {authors}
    + {Functions.mlang(item.journal, lang)} + {item.publication_year} + {item.volume !== null && ' ;' + item.volume} + {item.number !== null && ' (' + item.number + ')'} + {item.page !== '' && ' :' + item.page} + {item.pubmed_id !== '' && <> [PMID:]} + + ); + } +} + +export default PaperList; \ No newline at end of file diff --git a/src/database/item-type/paper/PaperTop.tsx b/src/database/item-type/paper/PaperTop.tsx new file mode 100644 index 0000000..2d6ea43 --- /dev/null +++ b/src/database/item-type/paper/PaperTop.tsx @@ -0,0 +1,15 @@ +import TopBase, { TopBaseProps } from '../lib/TopBase'; +import iconFile from '../../assets/images/icon_paper.gif'; + +class PaperTop extends TopBase { + + constructor(props: TopBaseProps) { + super(props); + this.type = 'paper'; + this.label = 'Paper'; + this.icon = iconFile; + this.description = '[en]Related paper collection.[/en][ja]関連論文[/ja]'; + } +} + +export default PaperTop; \ No newline at end of file diff --git a/src/database/item-type/paper/PaperUtil.tsx b/src/database/item-type/paper/PaperUtil.tsx new file mode 100644 index 0000000..419b6a6 --- /dev/null +++ b/src/database/item-type/paper/PaperUtil.tsx @@ -0,0 +1,22 @@ +import React from 'react'; +import { MultiLang } from '../../../config'; + +interface PubmedLinkProps { + lang: MultiLang; + pubmedId: string; +} + +const PubmedLink = (props: PubmedLinkProps) => { + const { pubmedId } = props; + if (pubmedId === '') { + return null; + } + const url = 'https://www.ncbi.nlm.nih.gov/pubmed/' + pubmedId; + return ({pubmedId}); +} + +const PaperUtil = { + PubmedLink, +} + +export default PaperUtil; \ No newline at end of file diff --git a/src/database/item-type/paper/index.tsx b/src/database/item-type/paper/index.tsx new file mode 100644 index 0000000..a781a94 --- /dev/null +++ b/src/database/item-type/paper/index.tsx @@ -0,0 +1,13 @@ +import PaperTop from './PaperTop'; +import PaperList from './PaperList'; +import PaperDetail from './PaperDetail'; +import PaperAdvancedSearch from './PaperAdvancedSearch'; + +const ItemTypePaper = { + Top: PaperTop, + List: PaperList, + Detail: PaperDetail, + AdvancedSearch: PaperAdvancedSearch, +}; + +export default ItemTypePaper; \ No newline at end of file diff --git a/src/database/item-type/presentation/PresentationAdvancedSearch.tsx b/src/database/item-type/presentation/PresentationAdvancedSearch.tsx new file mode 100644 index 0000000..d763def --- /dev/null +++ b/src/database/item-type/presentation/PresentationAdvancedSearch.tsx @@ -0,0 +1,46 @@ +import { ItemPresentationSubTypes } from '../../lib/ItemUtil'; +import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase'; + +class PresentationAdvancedSearch extends AdvancedSearchBase { + constructor(props: AdvancedSearchBaseProps) { + super(props); + this.type = 'presentation'; + this.title = 'Presentation'; + const now = new Date(); + const year = String(now.getFullYear()); + const month = String(now.getMonth() + 1); + const mday = String(now.getDate()); + this.state.values['title'] = ''; + this.state.values['keyword'] = ''; + this.state.values['description'] = ''; + this.state.values['doi'] = ''; + this.state.values['meeting_name'] = ''; + this.state.values['presentation_type'] = ''; + this.state.values['creator'] = ''; + this.state.values['publication_year'] = year; + this.state.values['publication_month'] = month; + this.state.values['publication_mday'] = mday; + this.state.values['file.preview.caption'] = ''; + this.state.values['file.presentation_file.original_file_name'] = ''; + this.setIgnoreKey('publication_year'); + this.setIgnoreKey('publication_month'); + this.setIgnoreKey('publication_mday'); + } + + getRows() { + const rows = [ + { label: '[en]Title[/en][ja]タイトル[/ja]', value: this.renderFieldInputText('title', 50) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: this.renderFieldInputText('keyword', 50) }, + { label: '[en]Description[/en][ja]概要[/ja]', value: this.renderFieldInputText('description', 50) }, + { label: 'ID', value: this.renderFieldInputText('doi', 50) }, + { label: '[en]Presentation Type[/en][ja]ファイル形式[/ja]', value: this.renderFieldSelect('presentation_type', ItemPresentationSubTypes) }, + { label: '[en]Creator[/en][ja]作成者[/ja]', value: this.renderFieldInputText('creator', 50) }, + { label: '[en]Date[/en][ja]日付[/ja]', value: this.renderFieldDate('', 'publication_year', 'publication_month', 'publication_mday') }, + { label: '[en]Caption[/en][ja]キャプション[/ja]', value: this.renderFieldInputText('file.preview.caption', 50) }, + { label: '[en]Presentation File[/en][ja]発表資料[/ja]', value: this.renderFieldInputText('file.presentation_file.original_file_name', 50) }, + ]; + return rows; + } +} + +export default PresentationAdvancedSearch; \ No newline at end of file diff --git a/src/database/item-type/presentation/PresentationDetail.tsx b/src/database/item-type/presentation/PresentationDetail.tsx new file mode 100644 index 0000000..2924449 --- /dev/null +++ b/src/database/item-type/presentation/PresentationDetail.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import Functions from '../../../functions'; +import { ItemPresentation } from '../../lib/ItemUtil'; +import DetailBase from '../lib/DetailBase'; +import ItemTypeField from '../lib/field'; +import PresentationUtil from './PresentationUtil'; + +class PresentationDetail extends DetailBase { + + getFields() { + const { lang } = this.props; + const item = this.props.item as ItemPresentation; + return [ + { label: 'ID', value: item.doi }, + { label: '[en]Language[/en][ja]言語[/ja]', value: }, + { label: '[en]Title[/en][ja]タイトル[/ja]', value: Functions.mlang(item.title, lang) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: }, + { label: '[en]Description[/en][ja]概要[/ja]', value: }, + { label: '[en]Date[/en][ja]日付[/ja]', value: }, + { label: '[en]Last Modified Date[/en][ja]最終更新日[/ja]', value: }, + { label: '[en]Created Date[/en][ja]作成日[/ja]', value: }, + { label: '[en]Contributor[/en][ja]登録者[/ja]', value: }, + { label: '[en]Item Type[/en][ja]アイテムタイプ[/ja]', value: item.item_type_display_name }, + { label: '[en]Change Log(History)[/en][ja]変更履歴[/ja]', value: }, + { label: '[en]Presentation Type[/en][ja]ファイル形式[/ja]', value: }, + { label: '[en]Creator[/en][ja]作成者[/ja]', value: }, + { label: '[en]Preview[/en][ja]プレビュー[/ja]', value: }, + { label: '[en]Presentation File[/en][ja]発表資料[/ja]', value: }, + { label: 'Readme', value: }, + { label: 'Rights', value: }, + { label: 'Index', value: }, + { label: '[en]Related to[/en][ja]関連アイテム[/ja]', value: }, + ]; + } +} + +export default PresentationDetail; \ No newline at end of file diff --git a/src/database/item-type/presentation/PresentationList.tsx b/src/database/item-type/presentation/PresentationList.tsx new file mode 100644 index 0000000..a6c8e61 --- /dev/null +++ b/src/database/item-type/presentation/PresentationList.tsx @@ -0,0 +1,33 @@ +import React, { Fragment } from 'react'; +import { Link } from 'react-router-dom'; +import Functions from '../../../functions'; +import iconFile from '../../assets/images/icon_presentation.gif'; +import { ItemPresentation } from '../../lib/ItemUtil'; +import ListBase, { ListBaseProps } from '../lib/ListBase'; +import PresentationUtil from './PresentationUtil'; + +class PresentationList extends ListBase { + + constructor(props: ListBaseProps) { + super(props); + this.label = 'Presentation'; + this.icon = iconFile; + } + + renderBody() { + const { lang } = this.props; + const item = this.props.item as ItemPresentation; + const authors = item.creator.map((author, i) => { + return {i > 0 && ', '}{Functions.mlang(author, lang)} + }); + return ( + <> + {Functions.mlang(item.title, lang)}
    +
    + {authors} + + ); + } +} + +export default PresentationList; \ No newline at end of file diff --git a/src/database/item-type/presentation/PresentationTop.tsx b/src/database/item-type/presentation/PresentationTop.tsx new file mode 100644 index 0000000..91a7e89 --- /dev/null +++ b/src/database/item-type/presentation/PresentationTop.tsx @@ -0,0 +1,18 @@ +import iconFile from '../../assets/images/icon_presentation.gif'; +import { ItemPresentationSubTypes } from '../../lib/ItemUtil'; +import TopBase, { TopBaseProps } from '../lib/TopBase'; + +class PresentationTop extends TopBase { + + constructor(props: TopBaseProps) { + super(props); + this.type = 'presentation'; + this.label = 'Presentation'; + this.icon = iconFile; + // DBPF: + this.description = '[en]Presentation files.[/en][ja]プレゼンテーション ファイル[/ja]'; + this.subTypes = ItemPresentationSubTypes; + } +} + +export default PresentationTop; \ No newline at end of file diff --git a/src/database/item-type/presentation/PresentationUtil.tsx b/src/database/item-type/presentation/PresentationUtil.tsx new file mode 100644 index 0000000..e5140bc --- /dev/null +++ b/src/database/item-type/presentation/PresentationUtil.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { MultiLang } from '../../../config'; +import { ItemPresentationSubType, ItemPresentationSubTypes } from '../../lib/ItemUtil'; + +interface PresentationTypeProps { + lang: MultiLang; + type: ItemPresentationSubType; +} + +const PresentationType = (props: PresentationTypeProps) => { + const { type } = props; + const subtype = ItemPresentationSubTypes.find((value) => { return value.type === type; }); + if (typeof subtype === 'undefined') { + return null; + } + return ({subtype.label}); +} + +const PresentationUtil = { + PresentationType, +} + +export default PresentationUtil; \ No newline at end of file diff --git a/src/database/item-type/presentation/index.tsx b/src/database/item-type/presentation/index.tsx new file mode 100644 index 0000000..13493a3 --- /dev/null +++ b/src/database/item-type/presentation/index.tsx @@ -0,0 +1,13 @@ +import PresentationTop from './PresentationTop'; +import PresentationList from './PresentationList'; +import PresentationDetail from './PresentationDetail'; +import PresentationAdvancedSearch from './PresentationAdvancedSearch'; + +const ItemTypePresentation = { + Top: PresentationTop, + List: PresentationList, + Detail: PresentationDetail, + AdvancedSearch: PresentationAdvancedSearch, +}; + +export default ItemTypePresentation; \ No newline at end of file diff --git a/src/database/item-type/simulator/SimulatorAdvancedSearch.tsx b/src/database/item-type/simulator/SimulatorAdvancedSearch.tsx new file mode 100644 index 0000000..463681a --- /dev/null +++ b/src/database/item-type/simulator/SimulatorAdvancedSearch.tsx @@ -0,0 +1,44 @@ +import { ItemSimulatorSubTypes } from '../../lib/ItemUtil'; +import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase'; + +class SimulatorAdvancedSearch extends AdvancedSearchBase { + + constructor(props: AdvancedSearchBaseProps) { + super(props); + this.type = 'simulator'; + this.title = 'Simulator'; + const now = new Date(); + const year = String(now.getFullYear()); + const month = String(now.getMonth() + 1); + const mday = String(now.getDate()); + this.state.values['title'] = ''; + this.state.values['keyword'] = ''; + this.state.values['description'] = ''; + this.state.values['doi'] = ''; + this.state.values['simulator_type'] = ''; + this.state.values['developer'] = ''; + this.state.values['publication_year'] = year; + this.state.values['publication_month'] = month; + this.state.values['publication_mday'] = mday; + this.state.values['file.preview.caption'] = ''; + this.setIgnoreKey('publication_year'); + this.setIgnoreKey('publication_month'); + this.setIgnoreKey('publication_mday'); + } + + getRows() { + const rows = [ + { label: '[en]Title[/en][ja]タイトル[/ja]', value: this.renderFieldInputText('title', 50) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: this.renderFieldInputText('keyword', 50) }, + { label: '[en]Description[/en][ja]概要[/ja]', value: this.renderFieldInputText('description', 50) }, + { label: 'ID', value: this.renderFieldInputText('doi', 50) }, + { label: '[en]Simulator Type[/en][ja]シミュレータータイプ[/ja]', value: this.renderFieldSelect('simulator_type', ItemSimulatorSubTypes) }, + { label: '[en]Developer[/en][ja]開発者[/ja]', value: this.renderFieldInputText('developer', 50) }, + { label: '[en]Date[/en][ja]日付[/ja]', value: this.renderFieldDate('', 'publication_year', 'publication_month', 'publication_mday') }, + { label: '[en]Caption[/en][ja]キャプション[/ja]', value: this.renderFieldInputText('file.preview.caption', 50) }, + ]; + return rows; + } +} + +export default SimulatorAdvancedSearch; diff --git a/src/database/item-type/simulator/SimulatorDetail.tsx b/src/database/item-type/simulator/SimulatorDetail.tsx new file mode 100644 index 0000000..d876cb2 --- /dev/null +++ b/src/database/item-type/simulator/SimulatorDetail.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import Functions from '../../../functions'; +import ItemUtil, { ItemSimulator } from '../../lib/ItemUtil'; +import DetailBase from '../lib/DetailBase'; +import ItemTypeField from '../lib/field'; +import SimPFLinkIcon from '../lib/field/SimPFLinkIcon'; +import SimulatorUtil from './SimulatorUtil'; + +class SimulatorDetail extends DetailBase { + + getFields() { + const { lang } = this.props; + const item = this.props.item as ItemSimulator; + const fields = [ + { label: 'ID', value: item.doi }, + { label: '[en]Language[/en][ja]言語[/ja]', value: }, + { label: '[en]Title[/en][ja]タイトル[/ja]', value: Functions.mlang(item.title, lang) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: }, + { label: '[en]Description[/en][ja]概要[/ja]', value: }, + { label: '[en]Date[/en][ja]日付[/ja]', value: }, + { label: '[en]Last Modified Date[/en][ja]最終更新日[/ja]', value: }, + { label: '[en]Created Date[/en][ja]作成日[/ja]', value: }, + { label: '[en]Contributor[/en][ja]登録者[/ja]', value: }, + { label: '[en]Item Type[/en][ja]アイテムタイプ[/ja]', value: item.item_type_display_name }, + { label: '[en]Change Log(History)[/en][ja]変更履歴[/ja]', value: }, + { label: '[en]Simulator Type[/en][ja]シミュレータータイプ[/ja]', value: }, + { label: '[en]Developer[/en][ja]開発者[/ja]', value: }, + { label: '[en]Preview[/en][ja]プレビュー[/ja]', value: }, + { label: '[en]Simulator File[/en][ja]ファイル[/ja]', value: }, + { label: 'Readme', value: }, + { label: 'Rights', value: }, + { label: 'Index', value: }, + { label: '[en]Related to[/en][ja]関連アイテム[/ja]', value: }, + ]; + const simpfLinkUrl = ItemUtil.getSimPFLinkUrl(item.item_id); + if (simpfLinkUrl !== '') { + const field = { label: 'Online Simulation', value: }; + fields.splice(14, 0, field); + } + return fields; + } +} + +export default SimulatorDetail; \ No newline at end of file diff --git a/src/database/item-type/simulator/SimulatorList.tsx b/src/database/item-type/simulator/SimulatorList.tsx new file mode 100644 index 0000000..3b91629 --- /dev/null +++ b/src/database/item-type/simulator/SimulatorList.tsx @@ -0,0 +1,31 @@ +import React, { Fragment } from 'react'; +import { Link } from 'react-router-dom'; +import Functions from '../../../functions'; +import iconFile from '../../assets/images/icon_simulator.gif'; +import { ItemSimulator } from '../../lib/ItemUtil'; +import ListBase, { ListBaseProps } from '../lib/ListBase'; + +class SimulatorList extends ListBase { + + constructor(props: ListBaseProps) { + super(props); + this.label = 'Simulator'; + this.icon = iconFile; + } + + renderBody() { + const { lang } = this.props; + const item = this.props.item as ItemSimulator; + const authors = item.developer.map((author, i) => { + return {i > 0 && ', '}{Functions.mlang(author, lang)} + }); + return ( + <> + {Functions.mlang(item.title, lang)}
    + {authors} + + ); + } +} + +export default SimulatorList; \ No newline at end of file diff --git a/src/database/item-type/simulator/SimulatorTop.tsx b/src/database/item-type/simulator/SimulatorTop.tsx new file mode 100644 index 0000000..af84099 --- /dev/null +++ b/src/database/item-type/simulator/SimulatorTop.tsx @@ -0,0 +1,19 @@ +import { ItemSimulatorSubTypes } from '../../lib/ItemUtil'; +import TopBase, { TopBaseProps } from '../lib/TopBase'; +import iconFile from '../../assets/images/icon_simulator.gif'; + +class SimulatorTop extends TopBase { + + constructor(props: TopBaseProps) { + super(props); + this.type = 'simulator'; + this.label = 'Simulator'; + this.icon = iconFile; + // DBPF: + // this.description = '[en]Programs/scripts for simulation.[/en][ja]シミュレーション用プログラム/スクリプト[/ja]'; + this.description = '[en]Programs for specific simulations.[/en][ja]特定のシミュレーション用プログラム[/ja]'; + this.subTypes = ItemSimulatorSubTypes; + } +} + +export default SimulatorTop; \ No newline at end of file diff --git a/src/database/item-type/simulator/SimulatorUtil.tsx b/src/database/item-type/simulator/SimulatorUtil.tsx new file mode 100644 index 0000000..adc52f5 --- /dev/null +++ b/src/database/item-type/simulator/SimulatorUtil.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { MultiLang } from '../../../config'; +import { ItemSimulatorSubType, ItemSimulatorSubTypes } from '../../lib/ItemUtil'; + +interface SimulatorTypeProps { + lang: MultiLang; + type: ItemSimulatorSubType; +} + +const SimulatorType = (props: SimulatorTypeProps) => { + const { type } = props; + const subtype = ItemSimulatorSubTypes.find((value) => { return value.type === type; }); + if (typeof subtype === 'undefined') { + return null; + } + return ({subtype.label}); +} + +const SimulatorUtil = { + SimulatorType, +} + +export default SimulatorUtil; \ No newline at end of file diff --git a/src/database/item-type/simulator/index.tsx b/src/database/item-type/simulator/index.tsx new file mode 100644 index 0000000..06c082d --- /dev/null +++ b/src/database/item-type/simulator/index.tsx @@ -0,0 +1,13 @@ +import SimulatorTop from './SimulatorTop'; +import SimulatorList from './SimulatorList'; +import SimulatorDetail from './SimulatorDetail'; +import SimulatorAdvancedSearch from './SimulatorAdvancedSearch'; + +const ItemTypeSimulator = { + Top: SimulatorTop, + List: SimulatorList, + Detail: SimulatorDetail, + AdvancedSearch: SimulatorAdvancedSearch, +}; + +export default ItemTypeSimulator; \ No newline at end of file diff --git a/src/database/item-type/stimulus/StimulusAdvancedSearch.tsx b/src/database/item-type/stimulus/StimulusAdvancedSearch.tsx new file mode 100644 index 0000000..d2a0bff --- /dev/null +++ b/src/database/item-type/stimulus/StimulusAdvancedSearch.tsx @@ -0,0 +1,44 @@ +import { ItemStimulusSubTypes } from '../../lib/ItemUtil'; +import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase'; + +class StimulusAdvancedSearch extends AdvancedSearchBase { + + constructor(props: AdvancedSearchBaseProps) { + super(props); + this.type = 'stimulus'; + this.title = 'Stimulus'; + const now = new Date(); + const year = String(now.getFullYear()); + const month = String(now.getMonth() + 1); + const mday = String(now.getDate()); + this.state.values['title'] = ''; + this.state.values['keyword'] = ''; + this.state.values['description'] = ''; + this.state.values['doi'] = ''; + this.state.values['stimulus_type'] = ''; + this.state.values['developer'] = ''; + this.state.values['publication_year'] = year; + this.state.values['publication_month'] = month; + this.state.values['publication_mday'] = mday; + this.state.values['file.preview.caption'] = ''; + this.setIgnoreKey('publication_year'); + this.setIgnoreKey('publication_month'); + this.setIgnoreKey('publication_mday'); + } + + getRows() { + const rows = [ + { label: '[en]Title[/en][ja]タイトル[/ja]', value: this.renderFieldInputText('title', 50) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: this.renderFieldInputText('keyword', 50) }, + { label: '[en]Description[/en][ja]概要[/ja]', value: this.renderFieldInputText('description', 50) }, + { label: 'ID', value: this.renderFieldInputText('doi', 50) }, + { label: '[en]Stimulus Type[/en][ja]刺激タイプ[/ja]', value: this.renderFieldSelect('stimulus_type', ItemStimulusSubTypes) }, + { label: '[en]Developer[/en][ja]開発者[/ja]', value: this.renderFieldInputText('developer', 50) }, + { label: '[en]Date[/en][ja]日付[/ja]', value: this.renderFieldDate('', 'publication_year', 'publication_month', 'publication_mday') }, + { label: '[en]Caption[/en][ja]キャプション[/ja]', value: this.renderFieldInputText('file.preview.caption', 50) }, + ]; + return rows; + } +} + +export default StimulusAdvancedSearch; diff --git a/src/database/item-type/stimulus/StimulusDetail.tsx b/src/database/item-type/stimulus/StimulusDetail.tsx new file mode 100644 index 0000000..2f16ad4 --- /dev/null +++ b/src/database/item-type/stimulus/StimulusDetail.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import Functions from '../../../functions'; +import ItemUtil, { ItemStimulus } from '../../lib/ItemUtil'; +import DetailBase from '../lib/DetailBase'; +import ItemTypeField from '../lib/field'; +import SimPFLinkIcon from '../lib/field/SimPFLinkIcon'; +import StimulusUtil from './StimulusUtil'; + +class StimulusDetail extends DetailBase { + + getFields() { + const { lang } = this.props; + const item = this.props.item as ItemStimulus; + const fields = [ + { label: 'ID', value: item.doi }, + { label: '[en]Language[/en][ja]言語[/ja]', value: }, + { label: '[en]Title[/en][ja]タイトル[/ja]', value: Functions.mlang(item.title, lang) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: }, + { label: '[en]Description[/en][ja]概要[/ja]', value: }, + { label: '[en]Date[/en][ja]日付[/ja]', value: }, + { label: '[en]Last Modified Date[/en][ja]最終更新日[/ja]', value: }, + { label: '[en]Created Date[/en][ja]作成日[/ja]', value: }, + { label: '[en]Contributor[/en][ja]登録者[/ja]', value: }, + { label: '[en]Item Type[/en][ja]アイテムタイプ[/ja]', value: item.item_type_display_name }, + { label: '[en]Change Log(History)[/en][ja]変更履歴[/ja]', value: }, + { label: '[en]Stimulus Type[/en][ja]刺激タイプ[/ja]', value: }, + { label: '[en]Developer[/en][ja]開発者[/ja]', value: }, + { label: '[en]Preview[/en][ja]プレビュー[/ja]', value: }, + { label: '[en]Stimulus File[/en][ja]ファイル[/ja]', value: }, + { label: 'Readme', value: }, + { label: 'Rights', value: }, + { label: 'Index', value: }, + { label: '[en]Related to[/en][ja]関連アイテム[/ja]', value: }, + ]; + const simpfLinkUrl = ItemUtil.getSimPFLinkUrl(item.item_id); + if (simpfLinkUrl !== '') { + const field = { label: 'Online Simulation', value: }; + fields.splice(14, 0, field); + } + return fields; + } +} + +export default StimulusDetail; diff --git a/src/database/item-type/stimulus/StimulusList.tsx b/src/database/item-type/stimulus/StimulusList.tsx new file mode 100644 index 0000000..baae6b7 --- /dev/null +++ b/src/database/item-type/stimulus/StimulusList.tsx @@ -0,0 +1,31 @@ +import React, { Fragment } from 'react'; +import { Link } from 'react-router-dom'; +import Functions from '../../../functions'; +import iconFile from '../../assets/images/icon_stimulus.gif'; +import { ItemStimulus } from '../../lib/ItemUtil'; +import ListBase, { ListBaseProps } from '../lib/ListBase'; + +class StimulusList extends ListBase { + + constructor(props: ListBaseProps) { + super(props); + this.label = 'Stimulus'; + this.icon = iconFile; + } + + renderBody() { + const { lang } = this.props; + const item = this.props.item as ItemStimulus; + const authors = item.developer.map((author, i) => { + return {i > 0 && ', '}{Functions.mlang(author, lang)} + }); + return ( + <> + {Functions.mlang(item.title, lang)}
    + {authors} + + ); + } +} + +export default StimulusList; \ No newline at end of file diff --git a/src/database/item-type/stimulus/StimulusTop.tsx b/src/database/item-type/stimulus/StimulusTop.tsx new file mode 100644 index 0000000..84be35d --- /dev/null +++ b/src/database/item-type/stimulus/StimulusTop.tsx @@ -0,0 +1,19 @@ +import { ItemStimulusSubTypes } from '../../lib/ItemUtil'; +import TopBase, { TopBaseProps } from '../lib/TopBase'; +import iconFile from '../../assets/images/icon_stimulus.gif'; + +class StimulusTop extends TopBase { + + constructor(props: TopBaseProps) { + super(props); + this.type = 'stimulus'; + this.label = 'Stimulus'; + this.icon = iconFile; + // DBPF: + // this.description = '[en]Picture, movie and program files for experimental stimuli.[/en][ja]実験用刺激プログラム/スクリプト[/ja]'; + this.description = '[en]Experimental stimuli.[/en][ja]実験用刺激[/ja]'; + this.subTypes = ItemStimulusSubTypes; + } +} + +export default StimulusTop; \ No newline at end of file diff --git a/src/database/item-type/stimulus/StimulusUtil.tsx b/src/database/item-type/stimulus/StimulusUtil.tsx new file mode 100644 index 0000000..3a0f8c8 --- /dev/null +++ b/src/database/item-type/stimulus/StimulusUtil.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { MultiLang } from '../../../config'; +import { ItemStimulusSubType, ItemStimulusSubTypes } from '../../lib/ItemUtil'; + +interface StimulusTypeProps { + lang: MultiLang; + type: ItemStimulusSubType; +} + +const StimulusType = (props: StimulusTypeProps) => { + const { type } = props; + const subtype = ItemStimulusSubTypes.find((value) => { return value.type === type; }); + if (typeof subtype === 'undefined') { + return null; + } + return ({subtype.label}); +} + +const StimulusUtil = { + StimulusType, +} + +export default StimulusUtil; \ No newline at end of file diff --git a/src/database/item-type/stimulus/index.tsx b/src/database/item-type/stimulus/index.tsx new file mode 100644 index 0000000..b01ff6c --- /dev/null +++ b/src/database/item-type/stimulus/index.tsx @@ -0,0 +1,13 @@ +import StimulusTop from './StimulusTop'; +import StimulusList from './StimulusList'; +import StimulusDetail from './StimulusDetail'; +import StimulusAdvancedSearch from './StimulusAdvancedSearch'; + +const ItemTypeStimulus = { + Top: StimulusTop, + List: StimulusList, + Detail: StimulusDetail, + AdvancedSearch: StimulusAdvancedSearch, +}; + +export default ItemTypeStimulus; \ No newline at end of file diff --git a/src/database/item-type/tool/ToolAdvancedSearch.tsx b/src/database/item-type/tool/ToolAdvancedSearch.tsx new file mode 100644 index 0000000..6c9a8d3 --- /dev/null +++ b/src/database/item-type/tool/ToolAdvancedSearch.tsx @@ -0,0 +1,46 @@ +import { ItemToolSubTypes } from '../../lib/ItemUtil'; +import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase'; + +class ToolAdvancedSearch extends AdvancedSearchBase { + + constructor(props: AdvancedSearchBaseProps) { + super(props); + this.type = 'tool'; + this.title = 'Tool'; + const now = new Date(); + const year = String(now.getFullYear()); + const month = String(now.getMonth() + 1); + const mday = String(now.getDate()); + this.state.values['title'] = ''; + this.state.values['keyword'] = ''; + this.state.values['description'] = ''; + this.state.values['doi'] = ''; + this.state.values['tool_type'] = ''; + this.state.values['developer'] = ''; + this.state.values['publication_year'] = year; + this.state.values['publication_month'] = month; + this.state.values['publication_mday'] = mday; + this.state.values['file.preview.caption'] = ''; + this.state.values['file.tool_data.original_file_name'] = ''; + this.setIgnoreKey('publication_year'); + this.setIgnoreKey('publication_month'); + this.setIgnoreKey('publication_mday'); + } + + getRows() { + const rows = [ + { label: '[en]Title[/en][ja]タイトル[/ja]', value: this.renderFieldInputText('title', 50) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: this.renderFieldInputText('keyword', 50) }, + { label: '[en]Description[/en][ja]概要[/ja]', value: this.renderFieldInputText('description', 50) }, + { label: 'ID', value: this.renderFieldInputText('doi', 50) }, + { label: '[en]Tool Type[/en][ja]ファイルタイプ[/ja]', value: this.renderFieldSelect('tool_type', ItemToolSubTypes) }, + { label: '[en]Developer[/en][ja]開発者[/ja]', value: this.renderFieldInputText('developer', 50) }, + { label: '[en]Date[/en][ja]日付[/ja]', value: this.renderFieldDate('', 'publication_year', 'publication_month', 'publication_mday') }, + { label: '[en]Caption[/en][ja]キャプション[/ja]', value: this.renderFieldInputText('file.preview.caption', 50) }, + { label: '[en]Tool File[/en][ja]ファイル[/ja]', value: this.renderFieldInputText('file.tool_data.original_file_name', 50) }, + ]; + return rows; + } +} + +export default ToolAdvancedSearch; diff --git a/src/database/item-type/tool/ToolDetail.tsx b/src/database/item-type/tool/ToolDetail.tsx new file mode 100644 index 0000000..aa30c02 --- /dev/null +++ b/src/database/item-type/tool/ToolDetail.tsx @@ -0,0 +1,43 @@ +import React from 'react'; +import Functions from '../../../functions'; +import ItemUtil, { ItemTool } from '../../lib/ItemUtil'; +import DetailBase from '../lib/DetailBase'; +import ItemTypeField from '../lib/field'; +import SimPFLinkIcon from '../lib/field/SimPFLinkIcon'; +import ToolUtil from './ToolUtil'; + +class ToolDetail extends DetailBase { + + getFields() { + const { lang } = this.props; + const item = this.props.item as ItemTool; + const fields = [ + { label: 'ID', value: item.doi }, + { label: '[en]Language[/en][ja]言語[/ja]', value: }, + { label: '[en]Title[/en][ja]タイトル[/ja]', value: Functions.mlang(item.title, lang) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: }, + { label: '[en]Description[/en][ja]概要[/ja]', value: }, + { label: '[en]Last Modified Date[/en][ja]最終更新日[/ja]', value: }, + { label: '[en]Created Date[/en][ja]作成日[/ja]', value: }, + { label: '[en]Contributor[/en][ja]登録者[/ja]', value: }, + { label: '[en]Item Type[/en][ja]アイテムタイプ[/ja]', value: item.item_type_display_name }, + { label: '[en]Change Log(History)[/en][ja]変更履歴[/ja]', value: }, + { label: '[en]Tool Type[/en][ja]ファイルタイプ[/ja]', value: }, + { label: '[en]Developer[/en][ja]開発者[/ja]', value: }, + { label: '[en]Preview[/en][ja]プレビュー[/ja]', value: }, + { label: '[en]Tool File[/en][ja]ファイル[/ja]', value: }, + { label: 'Readme', value: }, + { label: 'Rights', value: }, + { label: 'Index', value: }, + { label: '[en]Related to[/en][ja]関連アイテム[/ja]', value: }, + ]; + const simpfLinkUrl = ItemUtil.getSimPFLinkUrl(item.item_id); + if (simpfLinkUrl !== '') { + const field = { label: 'Online Simulation', value: }; + fields.splice(13, 0, field); + } + return fields; + } +} + +export default ToolDetail; \ No newline at end of file diff --git a/src/database/item-type/tool/ToolList.tsx b/src/database/item-type/tool/ToolList.tsx new file mode 100644 index 0000000..27ee027 --- /dev/null +++ b/src/database/item-type/tool/ToolList.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import Functions from '../../../functions'; +import iconFile from '../../assets/images/icon_tool.gif'; +import { ItemTool } from '../../lib/ItemUtil'; +import ListBase, { ListBaseProps } from '../lib/ListBase'; +import ToolUtil from './ToolUtil'; + +class ToolList extends ListBase { + + constructor(props: ListBaseProps) { + super(props); + this.label = 'Tool'; + this.icon = iconFile; + } + + renderBody() { + const { lang } = this.props; + const item = this.props.item as ItemTool; + return ( + <> + {Functions.mlang(item.title, lang)}
    + + + ); + } +} + +export default ToolList; \ No newline at end of file diff --git a/src/database/item-type/tool/ToolTop.tsx b/src/database/item-type/tool/ToolTop.tsx new file mode 100644 index 0000000..1ef6290 --- /dev/null +++ b/src/database/item-type/tool/ToolTop.tsx @@ -0,0 +1,19 @@ +import { ItemToolSubTypes } from '../../lib/ItemUtil'; +import TopBase, { TopBaseProps } from '../lib/TopBase'; +import iconFile from '../../assets/images/icon_tool.gif'; + +class ToolTop extends TopBase { + + constructor(props: TopBaseProps) { + super(props); + this.type = 'tool'; + this.label = 'Tool'; + this.icon = iconFile; + // DBPF: + // this.description = '[en]Tool programs/scripts.[/en][ja]データ解析用プログラム/スクリプト[/ja]'; + this.description = '[en]Tools for non-specific models or data.[/en][ja]特定のモデルやデータに限定しない汎用ツール[/ja]'; + this.subTypes = ItemToolSubTypes; + } +} + +export default ToolTop; \ No newline at end of file diff --git a/src/database/item-type/tool/ToolUtil.tsx b/src/database/item-type/tool/ToolUtil.tsx new file mode 100644 index 0000000..3b3864c --- /dev/null +++ b/src/database/item-type/tool/ToolUtil.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { MultiLang } from '../../../config'; +import { ItemToolSubType, ItemToolSubTypes } from '../../lib/ItemUtil'; + +interface ToolTypeProps { + lang: MultiLang; + type: ItemToolSubType; +} + +const ToolType = (props: ToolTypeProps) => { + const { type } = props; + const subtype = ItemToolSubTypes.find((value) => { return value.type === type; }); + if (typeof subtype === 'undefined') { + return null; + } + return ({subtype.label}); +} + +const ToolUtil = { + ToolType, +} + +export default ToolUtil; \ No newline at end of file diff --git a/src/database/item-type/tool/index.tsx b/src/database/item-type/tool/index.tsx new file mode 100644 index 0000000..23a334c --- /dev/null +++ b/src/database/item-type/tool/index.tsx @@ -0,0 +1,13 @@ +import ToolTop from './ToolTop'; +import ToolList from './ToolList'; +import ToolDetail from './ToolDetail'; +import ToolAdvancedSearch from './ToolAdvancedSearch'; + +const ItemTypeTool = { + Top: ToolTop, + List: ToolList, + Detail: ToolDetail, + AdvancedSearch: ToolAdvancedSearch, +}; + +export default ItemTypeTool; \ No newline at end of file diff --git a/src/database/item-type/url/UrlAdvancedSearch.tsx b/src/database/item-type/url/UrlAdvancedSearch.tsx new file mode 100644 index 0000000..2062516 --- /dev/null +++ b/src/database/item-type/url/UrlAdvancedSearch.tsx @@ -0,0 +1,28 @@ +import AdvancedSearchBase, { AdvancedSearchBaseProps } from '../lib/AdvancedSearchBase'; + +class UrlAdvancedSearch extends AdvancedSearchBase { + + constructor(props: AdvancedSearchBaseProps) { + super(props); + this.type = 'url'; + this.title = 'Url'; + this.state.values['title'] = ''; + this.state.values['keyword'] = ''; + this.state.values['description'] = ''; + this.state.values['doi'] = ''; + this.state.values['url'] = ''; + } + + getRows() { + const rows = [ + { label: '[en]Title[/en][ja]タイトル[/ja]', value: this.renderFieldInputText('title', 50) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: this.renderFieldInputText('keyword', 50) }, + { label: '[en]Description[/en][ja]概要[/ja]', value: this.renderFieldInputText('description', 50) }, + { label: 'ID', value: this.renderFieldInputText('doi', 50) }, + { label: 'URL', value: this.renderFieldInputText('url', 50) }, + ]; + return rows; + } +} + +export default UrlAdvancedSearch; diff --git a/src/database/item-type/url/UrlDetail.tsx b/src/database/item-type/url/UrlDetail.tsx new file mode 100644 index 0000000..7637fc6 --- /dev/null +++ b/src/database/item-type/url/UrlDetail.tsx @@ -0,0 +1,32 @@ +import React from 'react'; +import Functions from '../../../functions'; +import { ItemUrl } from '../../lib/ItemUtil'; +import DetailBase from '../lib/DetailBase'; +import ItemTypeField from '../lib/field'; +import UrlUtil from './UrlUtil'; + +class UrlDetail extends DetailBase { + + getFields() { + const { lang } = this.props; + const item = this.props.item as ItemUrl; + return [ + { label: 'ID', value: item.doi }, + { label: '[en]Language[/en][ja]言語[/ja]', value: }, + { label: '[en]Title[/en][ja]タイトル[/ja]', value: Functions.mlang(item.title, lang) }, + { label: '[en]Free Keywords[/en][ja]フリーキーワード[/ja]', value: }, + { label: '[en]Description[/en][ja]概要[/ja]', value: }, + { label: '[en]Last Modified Date[/en][ja]最終更新日[/ja]', value: }, + { label: '[en]Created Date[/en][ja]作成日[/ja]', value: }, + { label: '[en]Contributor[/en][ja]登録者[/ja]', value: }, + { label: '[en]Item Type[/en][ja]アイテムタイプ[/ja]', value: item.item_type_display_name }, + { label: '[en]Change Log(History)[/en][ja]変更履歴[/ja]', value: }, + { label: 'URL', value: {item.url} }, + { label: '[en]Banner File[/en][ja]バナー[/ja]', value: }, + { label: 'Index', value: }, + { label: '[en]Related to[/en][ja]関連アイテム[/ja]', value: }, + ]; + } +} + +export default UrlDetail; \ No newline at end of file diff --git a/src/database/item-type/url/UrlList.tsx b/src/database/item-type/url/UrlList.tsx new file mode 100644 index 0000000..16905b1 --- /dev/null +++ b/src/database/item-type/url/UrlList.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import Functions from '../../../functions'; +import iconFile from '../../assets/images/icon_url.gif'; +import { ItemUrl } from '../../lib/ItemUtil'; +import ListBase, { ListBaseProps } from '../lib/ListBase'; + +class UrlList extends ListBase { + + constructor(props: ListBaseProps) { + super(props); + this.label = 'Url'; + this.icon = iconFile; + } + + renderBody() { + const { lang } = this.props; + const item = this.props.item as ItemUrl; + return ( + <> + {Functions.mlang(item.title, lang)}
    + Link to {item.url} + + ); + } +} + +export default UrlList; \ No newline at end of file diff --git a/src/database/item-type/url/UrlTop.tsx b/src/database/item-type/url/UrlTop.tsx new file mode 100644 index 0000000..a811323 --- /dev/null +++ b/src/database/item-type/url/UrlTop.tsx @@ -0,0 +1,17 @@ +import TopBase, { TopBaseProps } from '../lib/TopBase'; +import iconFile from '../../assets/images/icon_url.gif'; + +class UrlTop extends TopBase { + + constructor(props: TopBaseProps) { + super(props); + this.type = 'url'; + this.label = 'Url'; + this.icon = iconFile; + // DBPF: + // this.description = '[en]Link information.[/en][ja]関連リンク[/ja]'; + this.description = '[en]Related web pages.[/en][ja]関連Webページ[/ja]'; + } +} + +export default UrlTop; \ No newline at end of file diff --git a/src/database/item-type/url/UrlUtil.tsx b/src/database/item-type/url/UrlUtil.tsx new file mode 100644 index 0000000..1dbbfd2 --- /dev/null +++ b/src/database/item-type/url/UrlUtil.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import { MultiLang } from '../../../config'; +import ItemUtil, { ItemBasicFile } from '../../lib/ItemUtil'; + +interface BannerFileProps { + lang: MultiLang; + file: ItemBasicFile[]; +} + +const BannerFile = (props: BannerFileProps) => { + const { file } = props; + const data = file.find((value) => { + return value.file_type_name === 'url_banner_file'; + }); + if (typeof data === 'undefined') { + return null; + } + const url = ItemUtil.getFileUrl(data); + return ( + banner + ); +} + +const UrlUtil = { + BannerFile, +} + +export default UrlUtil; diff --git a/src/database/item-type/url/index.tsx b/src/database/item-type/url/index.tsx new file mode 100644 index 0000000..b359df2 --- /dev/null +++ b/src/database/item-type/url/index.tsx @@ -0,0 +1,13 @@ +import UrlTop from './UrlTop'; +import UrlList from './UrlList'; +import UrlDetail from './UrlDetail'; +import UrlAdvancedSearch from './UrlAdvancedSearch'; + +const ItemTypeUrl = { + Top: UrlTop, + List: UrlList, + Detail: UrlDetail, + AdvancedSearch: UrlAdvancedSearch, +}; + +export default ItemTypeUrl; diff --git a/src/database/lib/AdvancedSearchQuery.ts b/src/database/lib/AdvancedSearchQuery.ts new file mode 100644 index 0000000..2b528f8 --- /dev/null +++ b/src/database/lib/AdvancedSearchQuery.ts @@ -0,0 +1,95 @@ +type AdvancedSearchQueryData = Map; + +class AdvancedSearchQuery { + + private dataset: AdvancedSearchQueryData = new Map(); + + empty() { + let ret = true; + this.dataset.forEach((data) => { + data.forEach((value) => { + value = value.trim(); + if (value.length !== 0) { + ret = false; + } + }); + }); + return ret; + } + + set(type: string, key: string, value: string) { + type = type.trim(); + key = key.trim(); + const data: URLSearchParams = this.dataset.has(type) ? this.dataset.get(type) as URLSearchParams : new URLSearchParams(); + data.set(key, value); + this.dataset.set(type, data); + } + + delete(type: string, key: string) { + type = type.trim(); + key = key.trim(); + const data: URLSearchParams = this.dataset.has(type) ? this.dataset.get(type) as URLSearchParams : new URLSearchParams(); + data.delete(key); + this.dataset.set(type, data); + } + + deleteType(type: string) { + type = type.trim(); + this.dataset.delete(type.trim()); + } + + getQueryParams() { + let ret: URLSearchParams = new URLSearchParams(); + this.dataset.forEach((data, type) => { + data.forEach((value, key) => { + value = value.trim(); + value.length > 0 && ret.set(type + '.' + key, value); + }); + }); + return ret; + } + + setByQueryString(queryString: string) { + const query = new URLSearchParams(queryString); + query.forEach((v, k) => { + const [type, ...key] = k.split('.'); + if (typeof key === 'undefined') { + return; + } + this.set(type, key.join('.'), v); + }); + } + + getSearchFilter() { + let filter: any = []; + this.dataset.forEach((data, type) => { + let filter2: any = []; + filter2.push({ + item_type_name: 'xnp' + type, + }); + data.forEach((value, key) => { + const regex = value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const file = key.match(/^file\.([^.]+)\.([^.]+)$/); + if (file !== null) { + const fileType = file[1]; + const subKey = file[2]; + // TODO: wait to support $elemMatch operation on lokijs + // - see: https://github.com/techfort/LokiJS/issues/736 + // const filter3: any = { + // file_type_name: fileType, + // [subKey]: { '$regex': regex } + // }; + // filter2.push({ file: { '$elemMatch': filter3 } }); + filter2.push({ 'file.file_type_name': fileType }); + filter2.push({ ['file.' + subKey]: { '$regex': [regex, 'i'] } }); + } else { + filter2.push({ [key]: { '$regex': [regex, 'i'] } }); + } + }); + filter.push({ '$and': filter2 }); + }); + return { '$or': filter }; + } +} + +export default AdvancedSearchQuery; \ No newline at end of file diff --git a/src/database/lib/DatabaseListIndex.tsx b/src/database/lib/DatabaseListIndex.tsx new file mode 100644 index 0000000..de500f7 --- /dev/null +++ b/src/database/lib/DatabaseListIndex.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import IndexUtil, { Index } from './IndexUtil'; +import iconFile from '../assets/images/icon_folder.gif'; +import { MultiLang } from '../../config'; + +interface Props { + lang: MultiLang; + index: Index; +} + +const ListIndexItem = (props: Props) => { + const url = IndexUtil.getUrl(props.index.id); + const numOfIndexes = IndexUtil.countChildren(props.index.id); + return ( + + + + + + + +
    + {props.index.title} + + {props.index.title} +
    + {numOfIndexes} indexes / {props.index.numOfItems} items +
    + ); +} + +const DatabaseListIndex = (props: Props) => { + const { lang } = props; + const children = IndexUtil.getChildren(props.index.id); + if (children.length === 0) { + return null; + } + const treeList = children.map((value: Index, idx) => { + const evenodd = idx % 2 === 0 ? 'even' : 'odd'; + return ( + + + + + + ); + }); + return ( + + + {treeList} + +
    + ); +} + +export default DatabaseListIndex; diff --git a/src/database/lib/DatabaseListItem.module.css b/src/database/lib/DatabaseListItem.module.css new file mode 100644 index 0000000..a2f6d4f --- /dev/null +++ b/src/database/lib/DatabaseListItem.module.css @@ -0,0 +1,11 @@ +.sortCriteria { + text-align: center; +} + +.pageNavi { + text-align: right; +} + +.pageNaviItem { + margin: 0 5px; +} \ No newline at end of file diff --git a/src/database/lib/DatabaseListItem.tsx b/src/database/lib/DatabaseListItem.tsx new file mode 100644 index 0000000..00c7844 --- /dev/null +++ b/src/database/lib/DatabaseListItem.tsx @@ -0,0 +1,241 @@ +import React, { ChangeEvent, Component } from 'react'; +import { RouteComponentProps } from 'react-router'; +import { Link, withRouter } from 'react-router-dom'; +import Loading from '../../common/lib/Loading'; +import { MultiLang } from '../../config'; +import Functions from '../../functions'; +import ItemType from '../item-type'; +import styles from './DatabaseListItem.module.css'; +import { Item, SearchFunc, SearchResult, SortCondition, SortConditionLimit, SortConditionOrderBy, SortConditionOrderDir } from './ItemUtil'; + +const SORT_CONDITION_DEFAULT: SortCondition = { + limit: 20, + page: 1, + orderBy: 'title', + orderDir: 1 +}; +const SORT_CONDITION_RANGE_ORDER_BY = ['title', 'doi', 'last_update_date', 'creation_date', 'publication_date']; +const SORT_CONDITION_RANGE_ORDER_DIR = ['0', '1']; +const SORT_CONDITION_RANGE_LIMIT = ['20', '50', '100']; + +interface Props extends RouteComponentProps { + lang: MultiLang; + url: string; + search: SearchFunc +} + +interface State { + loading: boolean; + condition: SortCondition; + result: SearchResult; +} + +class DatabaseListItem extends Component { + + private isActive = false; + + constructor(props: Props) { + super(props); + this.state = { + loading: true, + condition: this.getSortConditionByQuery(this.props.location.search), + result: { total: 0, data: [] } + }; + this.handleSelectOrderby = this.handleSelectOrderby.bind(this); + this.handleSelectItemcount = this.handleSelectItemcount.bind(this); + } + + componentDidMount() { + this.isActive = true; + this.props.search(this.state.condition, (result) => { + if (this.isActive) { + this.setState({ loading: false, result }); + } + }); + } + + componentDidUpdate(prevProps: Props, prevState: State) { + const condition = this.getSortConditionByQuery(this.props.location.search); + if (prevProps.url !== this.props.url || this.isConditionChanged(prevState.condition, condition)) { + this.props.search(condition, (result) => { + if (this.isActive) { + this.setState({ loading: false, result, condition }); + } + }); + } + } + + componentWillUnmount() { + this.isActive = false; + } + + handleSelectOrderby(event: ChangeEvent) { + const value = event.target.value; + const url = this.getListUrl({ orderby: value }); + this.props.history.push(url); + } + + handleSelectItemcount(event: ChangeEvent) { + const value = parseInt(event.target.value, 10); + const url = this.getListUrl({ limit: value }); + this.props.history.push(url); + } + + isConditionChanged(prev: SortCondition, next: SortCondition) { + return prev.limit !== next.limit || prev.orderBy !== next.orderBy || prev.orderDir !== next.orderDir || prev.page !== next.page; + } + + getListUrl(query: { orderby?: string, order_dir?: number, limit?: number, page?: number }) { + const newOrderBy: string = typeof query.orderby !== 'undefined' ? query.orderby : this.state.condition.orderBy; + const newOrderDir: number = typeof query.order_dir !== 'undefined' ? query.order_dir : this.state.condition.orderDir; + const newLimit: number = typeof query.limit !== 'undefined' ? query.limit : this.state.condition.limit; + let newPage: number = typeof query.page !== 'undefined' ? query.page : this.state.condition.page; + if (newLimit !== this.state.condition.limit || newOrderBy !== this.state.condition.orderBy) { + newPage = SORT_CONDITION_DEFAULT.page; + } + const params = new URLSearchParams({ + orderby: newOrderBy, + order_dir: String(newOrderDir), + itemcount: String(newLimit), + page: String(newPage), + }); + const join = this.props.url.indexOf('?') < 0 ? '?' : '&' + return this.props.url + join + params.toString(); + } + + getDefaultSortCondition() { + return Object.assign({}, SORT_CONDITION_DEFAULT); + }; + + getSortConditionByQuery(queryString: string) { + const query = new URLSearchParams(queryString); + const condition = this.getDefaultSortCondition(); + const orderby = query.get('orderby'); + if (orderby !== null && SORT_CONDITION_RANGE_ORDER_BY.includes(orderby)) { + condition.orderBy = orderby as SortConditionOrderBy; + } + const order_dir = query.get('order_dir'); + if (order_dir !== null && SORT_CONDITION_RANGE_ORDER_DIR.includes(order_dir)) { + condition.orderDir = parseInt(order_dir, 10) as SortConditionOrderDir; + } + const itemcount = query.get('itemcount'); + if (itemcount !== null && SORT_CONDITION_RANGE_LIMIT.includes(itemcount)) { + condition.limit = parseInt(itemcount, 10) as SortConditionLimit; + } + const page = query.get('page'); + if (page !== null && page.match(/^\d+$/) !== null) { + condition.page = parseInt(page, 10); + } + return condition; + } + + renderSortCriteria() { + const { lang } = this.props; + let orderDir; + if (this.state.condition.orderDir !== SortConditionOrderDir.ASC) { + const url = this.getListUrl({ order_dir: SortConditionOrderDir.ASC }); + orderDir = ( + ▼ ▲ + ); + } else { + const url = this.getListUrl({ order_dir: SortConditionOrderDir.DESC }); + orderDir = ( + ▼ ▲ + ); + } + return ( +
    + + + + + + + +
    + Order by  + +  {orderDir} + + No.Item per page  + +
    +
    + ); + }; + + renderPageNavi(result: SearchResult) { + const maxPage = Math.floor(result.total / this.state.condition.limit) + (result.total % this.state.condition.limit !== 0 ? 1 : 0); + const link = (title: string, page: number, id: string) => { + if (page === 0 || page === this.state.condition.page) { + return ({title}); + } + const url: string = this.getListUrl({ page: page }); + return ({title}); + } + let startPage = (this.state.condition.page - 4) > 1 ? this.state.condition.page - 4 : 1; + const endPage = (startPage + 9) > maxPage ? maxPage : startPage + 9; + if ((endPage - startPage) < 9) { + startPage = (endPage - 9) > 0 ? endPage - 9 : 1; + } + let pageLinks: JSX.Element[] = []; + pageLinks.push(link('PREV', this.state.condition.page - 1, 'p')); + for (let i = startPage; i <= endPage; i++) { + pageLinks.push(link(String(i), i, String(i))); + } + pageLinks.push(link('NEXT', this.state.condition.page >= maxPage ? 0 : this.state.condition.page + 1, 'n')); + return ( +
    + {pageLinks} +
    + ); + } + + render() { + const { lang } = this.props; + if (this.state.loading) { + return ; + } + const result = this.state.result; + if (result.data.length === 0) { + return ( +

    No items found.

    + ); + } + const startNum = 1 + this.state.condition.limit * (this.state.condition.page - 1); + let endNum = this.state.condition.limit * this.state.condition.page; + if (endNum > result.total) { + endNum = result.total; + } + const pageNavi = this.renderPageNavi(result); + const items = result.data.map((item: Item, idx) => { + const evenodd = idx % 2 === 0 ? 'even' : 'odd'; + return (); + }); + return ( + <> + {this.renderSortCriteria()} +

    {startNum} - {endNum} of {result.total} Items

    + {pageNavi} + + + {items} + +
    + {pageNavi} + + ); + } +} + +export default withRouter(DatabaseListItem); \ No newline at end of file diff --git a/src/database/lib/IndexUtil.ts b/src/database/lib/IndexUtil.ts new file mode 100644 index 0000000..5664ead --- /dev/null +++ b/src/database/lib/IndexUtil.ts @@ -0,0 +1,95 @@ +import loki from 'lokijs'; +import indexesJson from '../assets/tree.json'; + +export interface Index { + id: number; + title: string; + numOfItems: number; + parentId: number; + weight: number; +} + +export const INDEX_ID_ROOT = 1; +export const INDEX_ID_PUBLIC = 3; + +interface IndexData { + id: number; + title: string; + num_of_items: number; + children: IndexData[]; +} +type IndexesData = IndexData[]; + +class IndexUtil { + + private database: loki; + private indexes: Collection; + + constructor(json: IndexesData) { + this.database = new loki('database'); + this.indexes = this.database.addCollection('indexes'); + this.load(json); + } + + load(json: IndexesData): void { + const store = (indexesData: IndexesData, parentId: number) => { + indexesData.forEach((indexData: IndexData, idx) => { + const entry: Index = { + id: indexData.id, + title: indexData.title, + numOfItems: indexData.num_of_items, + parentId: parentId, + weight: idx, + }; + this.indexes.insert(entry); + store(indexData.children, indexData.id) + }); + } + store(json, INDEX_ID_ROOT); + } + + getUrl(id: number): string { + return '/database/list/' + String(id); + } + + get(indexId: number): Index | null { + const filter = { + 'id': indexId, + } + const res = this.indexes.findOne(filter); + return res; + } + + getChildren(indexId: number): Index[] { + const filter = { + 'parentId': indexId, + } + const res = this.indexes.chain().find(filter).simplesort('weight').data(); + return res; + } + + countChildren(indexId: number): number { + const filter = { + 'parentId': indexId, + } + const res = this.indexes.count(filter); + return res; + } + + getParents(parentId: number): Index[] { + let parents: Index[] = []; + const loop = (parentId: number) => { + if (parentId !== INDEX_ID_ROOT) { + const parent = this.get(parentId); + if (parent !== null) { + loop(parent.parentId); + parents.push(parent); + } + } + } + loop(parentId); + return parents; + } +} + +export default new IndexUtil(indexesJson); \ No newline at end of file diff --git a/src/database/lib/ItemUtil.ts b/src/database/lib/ItemUtil.ts new file mode 100644 index 0000000..1ecf8f6 --- /dev/null +++ b/src/database/lib/ItemUtil.ts @@ -0,0 +1,702 @@ +import AsyncLock from 'async-lock'; +import axios from 'axios'; +import loki from 'lokijs'; +import funcs from '../../functions'; +import simpfLinksJson from '../assets/simpf-links.json'; +import AdvancedSearchQuery from './AdvancedSearchQuery'; + +interface SimPFLink { + id: number; + url: string; +} + +interface ItemSubType { + type: T; + label: string; +} + +export type ItemSubTypes = readonly ItemSubType[]; + +export type ItemBasicLang = 'eng' | 'jpn' | 'fra' | 'deu' | 'esl' | 'ita' | 'dut' | 'sve' | 'nor' | 'dan' | 'fin' | 'por' | 'chi' | 'kor'; +export interface ItemBasicIndex { + index_id: number; + title: string; +} +export interface ItemBasicChangeLog { + log_date: number; + log: string; +} +export interface ItemBasicFile { + file_id: number; + original_file_name: string; + mime_type: string; + file_size: number; + caption: string; + timestamp: string; + file_type_name: string; + file_type_display_name: string; +} +export interface ItemCore { + item_id: number; + doi: string; +} +export interface ItemBasic extends ItemCore { + uid: number; + description: string; + last_update_date: number; + creation_date: number; + publication_year: number; + publication_month: number; + publication_mday: number; + lang: ItemBasicLang; + title: string; + item_type_display_name: string; + item_type_name: string; + uname: string; + name: string; + item_url: string; + index: ItemBasicIndex[]; + changelog: ItemBasicChangeLog[]; + related_to: number[]; + keyword: string[]; + file: ItemBasicFile[]; +} + +export interface ItemBinder extends ItemBasic { + extra: string; + item_link: number[]; +} + +export interface ItemBook extends ItemBasic { + classfication: string; + editor: string; + publisher: string; + isbn: string; + url: string; + attachment_dl_limit: number; + attachment_dl_notify: number; + author: string[]; +} + +// DBPF: +// export type ItemConferenceSubType = 'powerpoint' | 'pdf' | 'illustrator' | 'other'; +export type ItemConferenceSubType = 'powerpoint' | 'pdf' | 'other'; +export const ItemConferenceSubTypes: ItemSubTypes = [ + { type: 'powerpoint', label: 'PowerPoint' }, + { type: 'pdf', label: 'PDF' }, + // { type: 'illustrator', label: 'Illustrator' }, + { type: 'other', label: 'Other' }, +]; +export interface ItemConference extends ItemBasic { + presentation_type: ItemConferenceSubType; + conference_title: string; + place: string; + abstract: string; + conference_from_year: number; + conference_from_month: number; + conference_from_mday: number; + conference_to_year: number; + conference_to_month: number; + conference_to_mday: number; + attachment_dl_limit: number; + attachment_dl_notify: number; + author: string[]; +} + +export type ItemDataSubType = 'excel' | 'movie' | 'text' | 'picture' | 'other'; +export const ItemDataSubTypes: ItemSubTypes = [ + { type: 'excel', label: 'Excel' }, + { type: 'movie', label: 'Movie' }, + { type: 'text', label: 'Text' }, + { type: 'picture', label: 'Picture' }, + { type: 'other', label: 'Other' }, +]; +export interface ItemData extends ItemBasic { + data_type: ItemDataSubType; + rights: string; + readme: string; + use_cc: number; + cc_commercial_use: number; + cc_modification: number; + attachment_dl_limit: number; + attachment_dl_notify: number; + experimenter: string[]; +} + +// DBPF: +// export type ItemFilesSubType = 'pdf' | 'doc' | 'xls' | 'ppt' | 'docx' | 'xlsx' | 'pptx' | 'zip' | 'lzh' | 'mov' // CBSN extended +export type ItemFilesSubType = 'pdf' | 'doc' | 'xlsx' | 'pptx' | 'zip' | 'asf' | 'avi' | 'mov' | 'mp4' | 'wmv' | 'jpg'; +export const ItemFilesSubTypes: ItemSubTypes = [ + { type: 'pdf', label: 'pdf' }, + { type: 'doc', label: 'doc' }, + // { type: 'xls', label: 'xls' }, + // { type: 'ppt', label: 'ppt' }, + // { type: 'docx', label: 'docx' }, + { type: 'xlsx', label: 'xlsx' }, + { type: 'pptx', label: 'pptx' }, + { type: 'zip', label: 'zip' }, + // { type: 'lzh', label: 'lzh' }, + { type: 'asf', label: 'asf' }, + { type: 'avi', label: 'avi' }, + { type: 'mov', label: 'mov' }, + { type: 'mp4', label: 'mp4' }, + { type: 'wmv', label: 'wmv' }, + // { type: 'c', label: 'c' }, + // { type: 'txt', label: 'txt' }, + { type: 'jpg', label: 'jpg' }, +]; +export interface ItemFiles extends ItemBasic { + data_file_name: string; + data_file_mimetype: string; + data_file_filetype: string; +} + +export interface ItemMemo extends ItemBasic { + item_link: string; +} + +// DBPF: +// export type ItemModelSubType = 'matlab' | 'neuron' | 'original_program' | 'satellite' | 'genesis' | 'a_cell' | 'other'; +export type ItemModelSubType = 'isml' | 'neuron' | 'genesis' | 'other'; +export const ItemModelSubTypes: ItemSubTypes = [ + // { type: 'matlab', label: 'Matlab' }, + { type: 'isml', label: 'inSilicoML' }, + { type: 'neuron', label: 'Neuron' }, + // { type: 'original_program', label: 'Original Program' }, + // { type: 'satellite', label: 'Satellite' }, + { type: 'genesis', label: 'Genesis' }, + // { type: 'a_cell', label: 'A-Cell' }, + { type: 'other', label: 'Other' }, +]; +export interface ItemModel extends ItemBasic { + model_type: ItemModelSubType; + readme: string; + rights: string; + use_cc: number; + cc_commercial_use: number; + cc_modification: number; + attachment_dl_limit: number; + attachment_dl_notify: number; + creator: string[]; +} + +export interface ItemPaper extends ItemBasic { + journal: string; + volume: number; + number: number | null; + page: string; + abstract: string; + pubmed_id: string; + author: string[]; +} + +// DBPF: +// export type ItemPresentationSubType = 'powerpoint' | 'lotus' | 'justsystem' | 'html' | 'pdf' | 'other'; +export type ItemPresentationSubType = 'powerpoint' | 'pdf' | 'other'; +export const ItemPresentationSubTypes: ItemSubTypes = [ + { type: 'powerpoint', label: 'PowerPoint' }, + // { type: 'lotus', label: 'Lotus' }, + // { type: 'justsystem', label: 'JustSystem' }, + // { type: 'html', label: 'HTML' }, + { type: 'pdf', label: 'PDF' }, + { type: 'other', label: 'Other' }, +]; +export interface ItemPresentation extends ItemBasic { + presentation_type: ItemPresentationSubType; + use_cc: number; + cc_commercial_use: number; + cc_modification: number; + rights: string; + readme: string; + attachment_dl_limit: number; + attachment_dl_notify: number; + creator: string[]; +} + +// DBPF: +// export type ItemSimulatorSubType = 'matlab' | 'mathematica' | 'program' | 'other'; +export type ItemSimulatorSubType = 'matlab' | 'mathematica' | 'other'; +export const ItemSimulatorSubTypes: ItemSubTypes = [ + { type: 'matlab', label: 'Matlab' }, + { type: 'mathematica', label: 'Mathematica' }, + // { type: 'program', label: 'Program' }, + { type: 'other', label: 'Other' }, +]; +export interface ItemSimulator extends ItemBasic { + simulator_type: ItemSimulatorSubType; + readme: string; + rights: string; + use_cc: number; + cc_commercial_use: number; + cc_modification: number; + attachment_dl_limit: number; + attachment_dl_notify: number; + developer: string[]; +} + +// DBPF: +// export type ItemStimulusSubType = 'picture' | 'movie' | 'program' | 'other'; +export type ItemStimulusSubType = 'image' | 'movie' | 'sound' | 'program' | 'other'; +export const ItemStimulusSubTypes: ItemSubTypes = [ + // { type: 'picture', label: 'Picture' }, + { type: 'image', label: 'Image' }, + { type: 'movie', label: 'Movie' }, + { type: 'sound', label: 'Sound' }, + { type: 'program', label: 'Program' }, + { type: 'other', label: 'Other' }, +]; +export interface ItemStimulus extends ItemBasic { + stimulus_type: ItemStimulusSubType; + readme: string; + rights: string; + use_cc: number; + cc_commercial_use: number; + cc_modification: number; + attachment_dl_limit: number; + attachment_dl_notify: number; + developer: string[]; +} + +// DBPF: +// export type ItemToolSubType = 'matlab' | 'mathematica' | 'program' | 'other'; +export type ItemToolSubType = 'matlab' | 'mathematica' | 'other'; +export const ItemToolSubTypes: ItemSubTypes = [ + { type: 'matlab', label: 'Matlab' }, + { type: 'mathematica', label: 'Mathematica' }, + // { type: 'program', label: 'Program' }, + { type: 'other', label: 'Other' }, +]; +export interface ItemTool extends ItemBasic { + tool_type: ItemToolSubType; + readme: string; + rights: string; + use_cc: number; + cc_commercial_use: number; + cc_modification: number; + attachment_dl_limit: number; + attachment_dl_notify: number; + developer: string[]; +} + +export interface ItemUrl extends ItemBasic { + url: string; + url_count: number; +} + +export type Item = ItemBinder | ItemBook | ItemConference | ItemData | ItemFiles | ItemMemo | ItemModel | ItemPaper | ItemPresentation | ItemSimulator | ItemStimulus | ItemTool | ItemUrl; + +export type KeywordSearchType = 'all' | 'basic' | 'binder' | 'book' | 'conference' | 'data' | 'files' | 'memo' | 'model' | 'paper' | 'presentation' | 'simulator' | 'stimulus' | 'tool' | 'url'; +export interface KeywordSearchQuery { + type: KeywordSearchType; + keyword: string; +} +const KEYWORD_SEARCH_TYPE_RANGE = ['all', 'basic', 'binder', 'book', 'conference', 'files', 'data', 'memo', 'model', 'paper', 'presentation', 'simulator', 'stimulus', 'tool', 'url']; + +export type SortConditionLimit = 20 | 50 | 100; +export type SortConditionOrderBy = 'title' | 'doi' | 'last_update_date' | 'creation_date' | 'publication_date'; +export enum SortConditionOrderDir { ASC, DESC } + +export interface SortCondition { + limit: SortConditionLimit; + orderBy: SortConditionOrderBy; + orderDir: SortConditionOrderDir; + page: number; +} + +class ItemSorter { + + public orderBy: SortConditionOrderBy; + public orderDir: SortConditionOrderDir; + + constructor(condition: SortCondition) { + this.orderBy = condition.orderBy; + this.orderDir = condition.orderDir; + this.sort = this.sort.bind(this); + } + + sort(a: Item, b: Item) { + let av: string = ''; + let bv: string = ''; + switch (this.orderBy) { + case 'title': + av = a.title.toLocaleUpperCase(); + bv = b.title.toLocaleUpperCase(); + break; + case 'doi': + av = a.doi.toLocaleUpperCase(); + bv = b.doi.toLocaleUpperCase(); + break; + case 'last_update_date': + av = String(a.last_update_date); + bv = String(b.last_update_date); + break; + case 'creation_date': + av = String(a.creation_date); + bv = String(b.creation_date); + break; + case 'publication_date': + av = String(a.publication_year * 10000 + a.publication_month * 100 + a.publication_mday); + bv = String(b.publication_year * 10000 + b.publication_month * 100 + b.publication_mday); + break; + default: + break; + } + if (this.orderDir === SortConditionOrderDir.ASC) { + if (av > bv) return -1; + else if (av < bv) return 1; + } else { + if (av > bv) return 1; + else if (av < bv) return -1; + } + return 0; + } +} + +type GetResult = Item | null; +export interface GetCallbackFunc { (item: GetResult): void } +export interface SearchResult { + total: number; + data: Item[]; +} +export interface SearchCallbackFunc { (results: SearchResult): void } +export interface SearchFunc { (condition: SortCondition, func: SearchCallbackFunc): void } + +interface ItemLoadCallbackFunc { (items: Collection): void } + +class ItemUtil { + + private database: loki; + private items: Collection; + private simpfLinks: Collection; + private loading: boolean; + private callbacks: ItemLoadCallbackFunc[]; + + constructor() { + this.database = new loki('database'); + this.items = this.database.addCollection('items'); + this.simpfLinks = this.database.addCollection('simpf-links'); + this.loading = true; + this.callbacks = []; + this.load(); + } + + load(): void { + axios.get(process.env.PUBLIC_URL + '/database/items.json', { responseType: 'json' }).then((response) => { + const itemsJson = response.data as Item[]; + itemsJson.forEach((json: Item) => { + this.items.insert(json); + }); + const lock = new AsyncLock(); + lock.acquire('items', () => { + this.loading = false; + this.callbacks.forEach((callback) => { + callback(this.items); + }); + this.callbacks = []; + }); + }); + const simpfLinks = simpfLinksJson as SimPFLink[]; + simpfLinks.forEach((simpfLink: SimPFLink) => { + this.simpfLinks.insert(simpfLink); + }); + } + + registerItemLoadCallback(func: ItemLoadCallbackFunc): void { + const lock = new AsyncLock(); + lock.acquire('items', () => { + if (this.loading) { + this.callbacks.push(func); + } else { + func(this.items); + } + }); + } + + getUrl(item: ItemCore): string { + if (item.doi !== '') { + return '/database/item/id/' + funcs.escape(item.doi); + } + return '/database/item/' + String(item.item_id); + } + + getFileUrl(file: ItemBasicFile): string { + return process.env.PUBLIC_URL + '/database/file/' + String(file.file_id) + '/' + funcs.escape(file.original_file_name); + } + + getPreviewFileUrl(file: ItemBasicFile): string { + return process.env.PUBLIC_URL + '/database/file/' + String(file.file_id) + '.png'; + } + + getSearchByKeywordUrl(type: KeywordSearchType, keyword: string): string { + const params = new URLSearchParams({ type, keyword }); + return '/database/search?' + params.toString(); + } + + getItemTypeSearchUrl(type: string): string { + return '/database/search/itemtype/' + funcs.escape(type); + } + + getSearchByAdvancedKeywordsUrl(query: AdvancedSearchQuery): string { + const paramString = query.getQueryParams().toString(); + return '/database/search/advanced' + (paramString.length > 0 ? '?' + paramString : ''); + } + + getSearchKeywordByQuery(queryString: string): KeywordSearchQuery { + const query = new URLSearchParams(queryString); + const qtype = query.get('type'); + const type = qtype !== null && KEYWORD_SEARCH_TYPE_RANGE.includes(qtype) ? qtype as KeywordSearchType : 'all'; + const qkeyword = query.get('keyword'); + const keyword = qkeyword === null ? '' : qkeyword; + return ({ type, keyword }); + } + + getAdvancedSearchQueryByQuery(queryString: string): AdvancedSearchQuery { + const query: AdvancedSearchQuery = new AdvancedSearchQuery(); + query.setByQueryString(queryString); + return query; + } + + get(itemId: number, func: GetCallbackFunc): void { + this.registerItemLoadCallback((items) => { + const filter = { + item_id: itemId + } + const item = items.findOne(filter); + func(item); + }); + } + + getByDoi(doi: string, func: GetCallbackFunc): void { + this.registerItemLoadCallback((items) => { + const filter = { + doi: doi + } + const item = items.findOne(filter); + func(item); + }); + } + + getList(itemIds: number[], func: SearchCallbackFunc): void { + this.registerItemLoadCallback((items) => { + const filter = { + item_id: { + '$in': itemIds, + } + } + const sort = (a: Item, b: Item) => { + const aIdx = itemIds.findIndex((itemId) => { return a.item_id === itemId; }); + const bIdx = itemIds.findIndex((itemId) => { return b.item_id === itemId; }); + if (aIdx > bIdx) { + return 1; + } else if (aIdx < bIdx) { + return -1; + } + return 0; + } + const data = items.chain().find(filter).sort(sort).data(); + const res = { + total: data.length, + data: data, + } + func(res); + }); + } + + getListByIndexId(indexId: number, condition: SortCondition, func: SearchCallbackFunc): void { + this.registerItemLoadCallback((items) => { + const filter: any = { + 'index.index_id': indexId + }; + const offset = condition.limit * (condition.page - 1); + const result = items.chain().find(filter); + const itemSorter = new ItemSorter(condition); + const ret = { + total: result.count(), + data: result.sort(itemSorter.sort).offset(offset).limit(condition.limit).data() + }; + func(ret); + }); + } + + getListByItemType(itemType: string, subItemType: string, condition: SortCondition, func: SearchCallbackFunc): void { + this.registerItemLoadCallback((items) => { + let filter: any = { + item_type_name: 'xnp' + itemType, + } + if (subItemType !== '') { + switch (itemType) { + case 'conference': + filter.presentation_type = subItemType; + break; + case 'data': + filter.data_type = subItemType; + break; + case 'files': + filter.data_file_filetype = subItemType; + break; + case 'model': + filter.model_type = subItemType; + break; + case 'presentation': + filter.presentation_type = subItemType; + break; + case 'simulator': + filter.simulator_type = subItemType; + break; + case 'stimulus': + filter.stimulus_type = subItemType; + break; + case 'tool': + filter.tool_type = subItemType; + break; + default: + break; + } + } + const offset = condition.limit * (condition.page - 1); + const result = items.chain().find(filter); + const itemSorter = new ItemSorter(condition); + const ret = { + total: result.count(), + data: result.sort(itemSorter.sort).offset(offset).limit(condition.limit).data() + }; + func(ret); + }); + } + + getListByKeyword(type: KeywordSearchType, keyword: string, condition: SortCondition, func: SearchCallbackFunc): void { + this.registerItemLoadCallback((items) => { + const regex = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const num = keyword.match(/^[0-9]+$/) ? parseInt(keyword, 10) : null; + let filter: any = { '$or': [] }; + const appendToFilter = (type: string, strKeys: string[], numKeys: string[]) => { + const basicStrKeys: string[] = ['title', 'keyword', 'doi', 'description', 'uname', 'name', 'index.title']; + const basicNumKeys: string[] = []; + let filterItemType: any = { + item_type_name: 'xnp' + type, + '$or': [] + }; + let sKeys: string[] = basicStrKeys.concat(strKeys); + let nKeys: string[] = basicNumKeys.concat(numKeys); + sKeys.forEach((key) => { + let criteria: any = {}; + criteria[key] = { '$regex': [regex, 'i'] }; + filterItemType['$or'].push(criteria); + }); + if (num !== null) { + nKeys.forEach((key) => { + let criteria: any = {}; + criteria[key] = { '$eq': num }; + filterItemType['$or'].push(criteria); + }); + } + filter['$or'].push(filterItemType); + } + if (type === 'basic') { + filter['$or'].push({ 'title': { '$regex': [regex, 'i'] } }); + filter['$or'].push({ 'keyword': { '$regex': [regex, 'i'] } }); + } else { + if (type === 'all' || type === 'binder') { + const strKeys: string[] = ['doi', 'title', 'keyword', 'description']; + const numKeys: string[] = []; + appendToFilter('binder', strKeys, numKeys); + } + if (type === 'all' || type === 'book') { + const strKeys: string[] = ['doi', 'title', 'keyword', 'classification', 'editor', 'publisher', 'isbn', 'url', 'author', 'file.caption', 'file.original_file_name']; + const numKeys: string[] = []; + appendToFilter('book', strKeys, numKeys); + } + if (type === 'all' || type === 'conference') { + const strKeys: string[] = ['doi', 'title', 'conference_title', 'place', 'abstract', 'author', 'file.caption', 'file.original_file_name']; + const numKeys: string[] = ['conference_from_year', 'conference_from_month', 'conference_from_mday', 'conference_to_year', 'conference_to_month', 'conference_to_mday']; + appendToFilter('conference', strKeys, numKeys); + } + if (type === 'all' || type === 'data') { + const strKeys: string[] = ['doi', 'title', 'keyword', 'description', 'readme', 'rights', 'experimenter', 'data_type', 'file.caption', 'file.original_file_name']; + const numKeys: string[] = ['publication_year', 'publication_month', 'publication_mday']; + appendToFilter('data', strKeys, numKeys); + } + if (type === 'all' || type === 'files') { + const strKeys: string[] = ['doi', 'title', 'keyword', 'description', 'data_file_name', 'data_file_mimetype', 'data_file_filetype']; + const numKeys: string[] = []; + appendToFilter('files', strKeys, numKeys); + } + if (type === 'all' || type === 'memo') { + const strKeys: string[] = ['doi', 'title', 'keyword', 'description', 'item_link', 'file.original_file_name']; + const numKeys: string[] = []; + appendToFilter('memo', strKeys, numKeys); + } + if (type === 'all' || type === 'model') { + const strKeys: string[] = ['doi', 'title', 'keyword', 'description', 'readme', 'rights', 'creator', 'model_type', 'file.caption', 'file.original_file_name']; + const numKeys: string[] = []; + appendToFilter('model', strKeys, numKeys); + } + if (type === 'all' || type === 'paper') { + const strKeys: string[] = ['doi', 'title', 'keyword', 'journal', 'page', 'pubmed_id', 'author']; + const numKeys: string[] = ['publication_year', 'volume', 'number']; + appendToFilter('paper', strKeys, numKeys); + } + if (type === 'all' || type === 'presentation') { + const strKeys: string[] = ['doi', 'title', 'keyword', 'description', 'readme', 'rights', 'creator', 'presentation_type', 'file.caption', 'file.original_file_name']; + const numKeys: string[] = ['publication_year', 'publication_month', 'publication_mday']; + appendToFilter('presentation', strKeys, numKeys); + } + if (type === 'all' || type === 'simulator') { + const strKeys: string[] = ['doi', 'title', 'keyword', 'description', 'readme', 'rights', 'developer', 'simulator_type', 'file.caption', 'file.original_file_name']; + const numKeys: string[] = ['publication_year', 'publication_month', 'publication_mday']; + appendToFilter('simulator', strKeys, numKeys); + } + if (type === 'all' || type === 'stimulus') { + const strKeys: string[] = ['doi', 'title', 'keyword', 'description', 'readme', 'rights', 'developer', 'stimulus_type', 'file.caption', 'file.original_file_name']; + const numKeys: string[] = ['publication_year', 'publication_month', 'publication_mday']; + appendToFilter('stimulus', strKeys, numKeys); + } + if (type === 'all' || type === 'tool') { + const strKeys: string[] = ['doi', 'title', 'keyword', 'description', 'readme', 'rights', 'developer', 'tool_type', 'file.caption', 'file.original_file_name']; + const numKeys: string[] = []; + appendToFilter('tool', strKeys, numKeys); + } + if (type === 'all' || type === 'url') { + const strKeys: string[] = ['doi', 'title', 'keyword', 'url', 'file.original_file_name']; + const numKeys: string[] = []; + appendToFilter('url', strKeys, numKeys); + } + if (type !== 'all') { + filter['item_type_name'] = 'xnp' + type; + } + } + const offset = condition.limit * (condition.page - 1); + const result = items.chain().find(filter); + const itemSorter = new ItemSorter(condition); + const ret = { + total: result.count(), + data: result.sort(itemSorter.sort).offset(offset).limit(condition.limit).data() + }; + func(ret); + }); + } + + getListByAdvancedSearchQuery(query: AdvancedSearchQuery, condition: SortCondition, func: SearchCallbackFunc): void { + this.registerItemLoadCallback((items) => { + const filter: any = query.getSearchFilter(); + const offset = condition.limit * (condition.page - 1); + const result = items.chain().find(filter); + const itemSorter = new ItemSorter(condition); + const ret = { + total: result.count(), + data: result.sort(itemSorter.sort).offset(offset).limit(condition.limit).data() + }; + func(ret); + }); + } + + getSimPFLinkUrl(itemId: number) { + const simpfLink = this.simpfLinks.findOne({ id: itemId }); + if (simpfLink === null) { + return ''; + } + return simpfLink.url; + } +} + +export default new ItemUtil(); \ No newline at end of file diff --git a/src/functions.ts b/src/functions.ts new file mode 100644 index 0000000..72a1c0c --- /dev/null +++ b/src/functions.ts @@ -0,0 +1,130 @@ +import XRegExp from 'xregexp'; +import Config, { MultiLang } from './config'; + +const escape = (str: string) => { + return encodeURIComponent(str).replace(/[!'()*]/g, (c) => { + return '%' + c.charCodeAt(0).toString(16); + }); +} + +const unescape = (str: string) => { + return decodeURIComponent(str); +} + +const htmlspecialchars = (str: string) => { + return str.replace(/(<|>|&|'|")/g, (match) => { + switch (match) { + case '<': + return '<'; + case '>': + return '>'; + case '&': + return '&'; + case '\'': + return '''; + case '"': + return '"'; + } + return ''; + }); +} + +const camelCase = (str: string) => { + return str.replace(/[-_](.)/g, (...matches) => { + return matches[1].toUpperCase(); + }); +} + +const snakeCase = (str: string) => { + var camel = camelCase(str); + return camel.replace(/[A-Z]/g, (...matches) => { + return "_" + matches[0].charAt(0).toLowerCase(); + }); +} + +const pascalCase = (str: string) => { + var camel = camelCase(str); + return camel.charAt(0).toUpperCase() + camel.slice(1); +} + +const base64Encode = (str: string) => { + return btoa(unescape(encodeURIComponent(str))); +} + +const base64Decode = (str: string) => { + return decodeURIComponent(escape(atob(str))); +} + +const ordinal = (num: number) => { + const hundred = num % 100; + if (hundred >= 10 && hundred <= 20) { + return 'th'; + } + const ten = num % 10; + const suffix = ['st', 'nd', 'rd']; + return ten > 0 && ten < 4 ? suffix[ten - 1] : 'th'; +} + +const mlang = (str: string, lang: MultiLang) => { + const mlLangs = ['en', 'ja']; + // escape brackets inside of + let text = str.replace(/(]*)(>)/isg, (whole, m1, m2, m3) => { + if (m2.match(/type=["']?(?:text|hidden)["']?/is)) { + return m1 + m2.replace(/\[/g, '__ml[ml__') + m3; + } + return whole; + }); + // escape brackets inside of + text = text.replace(/(]*>)(.*)(<\/textarea>)/isg, (whole, m1, m2, m3) => { + return m1 + m2.replace(/\[/g, '__ml[ml__') + m3; + }); + // simple pattern to strip selected lang_tags + const re = new RegExp('\\[/?(?:[^\\]]+\\|)?' + lang + '(?:\\|[^\\]]+)?\\](?:
    )?', 'g'); + text = text.replace(re, ''); + // eliminate description between the other language tags. + mlLangs.forEach((mlLang) => { + if (mlLang !== lang) { + const re = XRegExp('\\[(?:[^/][^\\]]+\\|)?' + mlLang + '(?:\\|[^\\]]+)?\\].*?\\[/(?:[^\\]]+\\|)?' + mlLang + '(?:\\|[^\\]]+)?\\](?:
    )?', 'isg'); + text = text.replace(re, (whole) => { + return whole.match(/<\/table>/) ? whole : ''; + }); + } + }); + // unescape brackets inside of + text = text.replace(/(]*>)(.*)(<\/textarea>)/isg, (whole, m1, m2, m3) => { + return m1 + m2.replace(/__ml\[ml__/g, '[') + m3; + }); + // unescape brackets inside of + text = text.replace(/(]*)(>)/isg, (whole, m1, m2, m3) => { + if (m2.match(/type=["']?(?:text|hidden)["']?/is)) { + return m1 + m2.replace(/__ml\[ml__/g, '[') + m3; + } + return whole; + }); + return text; +} + +const siteTitle = (lang: MultiLang) => { + return mlang(Config.SITE_TITLE, lang); +} + +const siteSlogan = (lang: MultiLang) => { + return mlang(Config.SITE_SLOGAN, lang); +} + +const Functions = { + escape, + unescape, + htmlspecialchars, + camelCase, + snakeCase, + pascalCase, + base64Encode, + base64Decode, + ordinal, + mlang, + siteTitle, + siteSlogan, +}; + +export default Functions; \ No newline at end of file diff --git a/src/index.css b/src/index.css index ec2585e..2daa7e9 100644 --- a/src/index.css +++ b/src/index.css @@ -1,13 +1 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; -} +@import-normalize; diff --git a/src/index.tsx b/src/index.tsx index 87d1be5..aef507a 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,3 +1,5 @@ +import 'react-app-polyfill/ie11'; +import 'react-app-polyfill/stable'; import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; diff --git a/src/logo.svg b/src/logo.svg deleted file mode 100644 index 6b60c10..0000000 --- a/src/logo.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/mediawiki/MediaWiki.tsx b/src/mediawiki/MediaWiki.tsx new file mode 100644 index 0000000..acd8308 --- /dev/null +++ b/src/mediawiki/MediaWiki.tsx @@ -0,0 +1,100 @@ +import React, { Component } from 'react'; +import Helmet from 'react-helmet'; +import { Link } from 'react-router-dom'; +import Loading from '../common/lib/Loading'; +import PageNotFound from '../common/lib/PageNotFound'; +import XoopsCode from '../common/lib/XoopsCode'; +import { MultiLang } from '../config'; +import Functions from '../functions'; +import MediaWikiUtils, { MediaWikiPageData } from './lib/MediaWikiUtils'; +import './assets/style.css'; +import NoticeSiteHasBeenArchived from '../common/lib/NoticeSiteHasBeenArchived'; + +interface Props { + lang: MultiLang; + name: string; +} + +interface State { + loading: boolean; + page: MediaWikiPageData | null; +} + +class MediaWiki extends Component { + + private isActive: boolean; + + constructor(props: Props) { + super(props); + this.state = { + loading: true, + page: null, + }; + this.isActive = false; + } + + componentDidMount() { + const { name } = this.props; + this.isActive = true; + this.updatePage(name); + } + + componentDidUpdate(prevProps: Props, prevState: State) { + const { name } = this.props; + const prevName = prevProps.name; + if (name !== prevName) { + this.setState({ loading: true, page: null }); + this.updatePage(name); + } + } + + componentWillUnmount() { + this.isActive = false; + } + + updatePage(name: string) { + this.isActive = true; + MediaWikiUtils.getPage(name, (page: MediaWikiPageData | null) => { + if (this.isActive) { + this.setState({ loading: false, page }); + } + }) + } + + render() { + const { lang } = this.props; + const { loading, page } = this.state; + if (loading) { + return ; + } + if (page === null) { + return ; + } + return ( +
    + + {Functions.mlang(page.title, lang)} - {Functions.siteTitle(lang)} + + +
    +
    + メインページ (Japanese) + | + Main Page (English) +
    +
    +
    +
    +

    {Functions.mlang(page.title, lang)}

    +
    +
    + +
    +
    +
    +
    + ); + } +} + +export default MediaWiki; diff --git a/src/mediawiki/MediaWikiXoopsPathRedirect.tsx b/src/mediawiki/MediaWikiXoopsPathRedirect.tsx new file mode 100644 index 0000000..6a345db --- /dev/null +++ b/src/mediawiki/MediaWikiXoopsPathRedirect.tsx @@ -0,0 +1,35 @@ +import React, { Component } from 'react'; +import { Redirect, RouteComponentProps, withRouter } from 'react-router'; +import PageNotFound from '../common/lib/PageNotFound'; +import { MultiLang } from '../config'; + +interface Props extends RouteComponentProps { + lang: MultiLang; +} + +class MediaWikiXoopsPathRedirect extends Component { + + getRedirectUrl(): string { + const { location } = this.props; + const name = 'mediawiki'; + const pathname = location.pathname || ''; + const search = new RegExp(`^/modules/${name}/(?:index.php/)?([^/]*)$`); + const matches = pathname.match(search); + if (matches === null) { + return ''; + } + const path = matches[1] || ''; + return '/' + name + '/' + path; + } + + render() { + const { lang } = this.props; + const url = this.getRedirectUrl(); + if (url === '') { + return ; + } + return ; + } +} + +export default withRouter(MediaWikiXoopsPathRedirect); diff --git a/src/mediawiki/assets/style.css b/src/mediawiki/assets/style.css new file mode 100644 index 0000000..4294fd6 --- /dev/null +++ b/src/mediawiki/assets/style.css @@ -0,0 +1,261 @@ +.mediawiki { + font-size: 0.875em; + line-height: 1.6; +} +.mediawiki .mw-content-text { + margin: 15px 0; +} +.mediawiki * { + box-sizing: content-box; +} +.mediawiki h1, +.mediawiki h2, +.mediawiki h3, +.mediawiki h4, +.mediawiki h5, +.mediawiki h6 { + color: black !important; + font-weight: bold; + page-break-after: avoid; + background: none; + margin: 0; + overflow: hidden; + padding-top: 0.5em; + padding-bottom: 0.17em; + border-bottom: 1px solid #aaa; +} +.mediawiki ul { + line-height: 1.5em; + margin: 0.3em 0 0 1.6em; + padding: 0; + list-style-type: disc; + list-style-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAANAQMAAABb8jbLAAAABlBMVEX///8AUow5QSOjAAAAAXRSTlMAQObYZgAAABNJREFUCB1jYEABBQw/wLCAgQEAGpIDyT0IVcsAAAAASUVORK5CYII=); +} +.mediawiki ol { + line-height: 1.5em; + margin: 0.3em 0 0 3.2em; + padding: 0; + list-style-image: none; +} +.mediawiki li { + margin-bottom: 0.1em; +} +.mediawiki dt { + font-weight: bold; + margin-bottom: 0.1em; +} +.mediawiki dl { + margin-top: 0.2em; + margin-bottom: 0.5em; +} +.mediawiki dd { + line-height: 1.5em; + margin-left: 1.6em; + margin-bottom: 0.1em; +} +.mediawiki q { + font-style: italic; +} +.mediawiki pre, +.mediawiki code, +.mediawiki tt, +.mediawiki kbd, +.mediawiki samp, +.mediawiki .mw-code { + font-family: monospace, Courier; + padding: 1em 0; + color: black; + background-color: #f9f9f9; + border: 1pt dashed black; + white-space: pre; + font-size: 8pt; + overflow: auto; +} +.mediawiki table { + font-size: 100%; +} +.mediawiki fieldset { + border: 1px solid #2f6fab; + margin: 1em 0 1em 0; + padding: 0 1em 1em; + line-height: 1.5em; +} +.mediawiki fieldset.nested { + margin: 0 0 0.5em 0; + padding: 0 0.5em 0.5em; +} +.mediawiki legend { + padding: 0.5em; + font-size: 95%; +} +.mediawiki p { + margin: 1em 0; + line-height: 1.2em; +} +.mediawiki pre, +.mediawiki .mw-code { + border: 1pt dashed black; + white-space: pre; + font-size: 8pt; + overflow: auto; + padding: 1em 0; + background: white; + color: black; +} +.mediawiki table.small { + font-size: 100%; +} +.mediawiki table.listing, +.mediawiki table.listing td { + border: 1pt solid black; + border-collapse: collapse; +} +.mediawiki mark { + background-color: yellow; + color: black; +} +.mediawiki .mw-content hr { + height: 1px; + color: #aaa; + background-color: #aaa; + border: 0; + margin: 0.2em 0; +} +.mediawiki abbr[title], +.mediawiki .explain[title] { + border-bottom: 1px dotted; + cursor: help; +} +.mediawiki img.tex { + vertical-align: middle; +} +.mediawiki span.texhtml { + font-family: serif; +} +.mediawiki .center { + width: 100%; + text-align: center; +} +.mediawiki .center * { + margin-left: auto; + margin-right: auto; +} +.mediawiki .small { + font-size: 94%; +} + +.mediawiki .mw-content .thumbcaption { + text-align: left; +} +.mediawiki .mw-infobox { + border: 2px solid #ff7f00; + margin: 0.5em; + clear: left; + overflow: hidden; +} +.mediawiki .mw-infobox-left { + margin: 7px; + float: left; + width: 35px; +} +.mediawiki .mw-infobox-right { + margin: 0.5em 0.5em 0.5em 49px; +} +.mediawiki .mw-datatable { + border-collapse: collapse; +} +.mediawiki .mw-datatable, +.mediawiki .mw-datatable td, +.mediawiki .mw-datatable th { + border: 1px solid #aaaaaa; + padding: 0 0.15em 0 0.15em; +} +.mediawiki .mw-datatable th { + background-color: #ddddff; +} +.mediawiki .mw-datatable td { + background-color: #ffffff; +} +.mediawiki .mw-datatable tr:hover td { + background-color: #eeeeff; +} + +.mediawiki .mw-header .navigation a { + margin: 0 5px; +} + +.mediawiki .mw-content .toc { + display: table; + padding: 7px; + border: 1px solid #aaa; + background-color: #f9f9f9; + font-size: 90%; +} +.mediawiki .mw-content .toc ul { + margin: 0.3em 0; + text-align: left; + list-style-type: none; + list-style-image: none; + margin-left: 0; + padding: 0; + text-align: left; +} +.mediawiki .mw-content .toc ul ul { + margin: 0 0 0 2em; +} +.mediawiki .mw-content .toc ul ul { + margin: 0 0 0 2em; +} +.mediawiki .mw-content .toc .toctoggle { + font-size: 94%; +} +.mediawiki .mw-content .toc h2 { + display: inline; + border: none; + padding: 0; + font-size: 100%; + font-weight: bold; +} +.mediawiki .mw-content .toc #toctitle { + text-align: center; +} +.mediawiki div.tright { + margin: 0.5em 0 1.3em 1.4em; +} +.mediawiki div.thumb { + margin-bottom: 0.5em; + width: auto; + background-color: transparent; +} + +.mediawiki div.tleft { + margin: 0.5em 1.4em 1.3em 0; +} +.mediawiki div.tright, +.mediawiki div.floatright, +.mediawiki table.floatright { + clear: right; + float: right; +} +.mediawiki div.thumb { + margin-bottom: 0.5em; + width: auto; + background-color: transparent; +} +.mediawiki div.thumbinner { + border: 1px solid #ccc; + padding: 3px !important; + background-color: #f9f9f9; + font-size: 94%; + text-align: center; + overflow: hidden; +} +.mediawiki .thumbcaption { + border: none; + line-height: 1.4em; + padding: 3px !important; + font-size: 94%; +} +.mediawiki .thumbimage { + border: 1px solid #ccc; +} diff --git a/src/mediawiki/lib/MediaWikiUtils.ts b/src/mediawiki/lib/MediaWikiUtils.ts new file mode 100644 index 0000000..e4d2808 --- /dev/null +++ b/src/mediawiki/lib/MediaWikiUtils.ts @@ -0,0 +1,47 @@ +import axios from 'axios'; +import loki from 'lokijs'; +import contentsJson from '../assets/contents.json'; +import Functions from '../../functions'; + +export interface MediaWikiPageData { + title: string; + text: string; +} + +export interface MediaWikiContentData { + id: number; + title: string; +} + +export type GetContentCallback = (page: MediaWikiPageData | null) => void; + +class MediaWikiUtils { + + private database: loki; + private contents: Collection; + + constructor(json: MediaWikiContentData[]) { + this.database = new loki('mediawiki'); + this.contents = this.database.addCollection('contents'); + json.forEach((data) => { + this.contents.insert(data); + }); + } + + getPage(name: string, callback: GetContentCallback): void { + const title = Functions.unescape(name).replace(/_/g, ' '); + const content = this.contents.findOne({ title }); + if (content === null) { + callback(null); + } else { + axios.get('/mediawiki/contents/' + content.id + '.json').then((response) => { + const page = response.data as MediaWikiPageData; + callback(page); + }).catch(e => { + callback(null); + }); + } + } +} + +export default new MediaWikiUtils(contentsJson); \ No newline at end of file diff --git a/src/pico/Pico.tsx b/src/pico/Pico.tsx new file mode 100644 index 0000000..6ce402d --- /dev/null +++ b/src/pico/Pico.tsx @@ -0,0 +1,61 @@ +import React from 'react'; +import { Redirect, Route, RouteComponentProps, Switch } from 'react-router-dom'; +import PageNotFound from '../common/lib/PageNotFound'; +import { MultiLang } from '../config'; +import './assets/pico_main.css'; +import PicoUtils from './lib/PicoUtils'; +import PicoCategory from './PicoCategory'; +import PicoContent from './PicoContent'; +import PicoIndex from './PicoIndex'; +import PicoMenu from './PicoMenu'; + +interface Props { + lang: MultiLang; + name: string; +} + +const Pico = (props: Props) => { + const { lang, name } = props; + return ( + <> + + } /> + ) => { + const { location } = props; + const { pathname, search } = location; + const path = pathname.replace('/' + name + '/', ''); + if (path === '' || path === 'index.php') { + const params = new URLSearchParams(search); + const paramCatId = params.get('cat_id'); + if (paramCatId !== null && paramCatId.match(/^\d+$/)) { + const catId = parseInt(paramCatId, 10); + return ; + } + const paramContentId = params.get('content_id'); + if (paramContentId !== null && paramContentId.match(/^\d+$/)) { + const contentId = parseInt(paramContentId, 10); + return ; + } + const paramPage = params.get('page'); + if (paramPage !== null && paramPage === 'menu') { + return ; + } + return ; + } + const category = PicoUtils.getCategoryByPath(name, path); + if (category !== null) { + return ; + } + const content = PicoUtils.getContentByPath(name, path); + if (content !== null) { + return ; + } + return ; + }} /> + + + + ); +} + +export default Pico; diff --git a/src/pico/PicoCategory.tsx b/src/pico/PicoCategory.tsx new file mode 100644 index 0000000..224fd0b --- /dev/null +++ b/src/pico/PicoCategory.tsx @@ -0,0 +1,84 @@ +import React, { Fragment } from 'react'; +import Helmet from 'react-helmet'; +import { Link } from 'react-router-dom'; +import PageNotFound from '../common/lib/PageNotFound'; +import { MultiLang } from '../config'; +import Functions from '../functions'; +import PicoUtils, { PicoCategoryData, PicoContentData } from './lib/PicoUtils'; + +interface Props { + lang: MultiLang; + name: string; + catId: number; +} + +const PicoCategory = (props: Props) => { + const { lang, name, catId } = props; + const pico = PicoUtils.getModule(name); + if (pico === null) { + return ; + } + const category = PicoUtils.getCategory(name, catId); + if (category === null) { + return ; + } + const parentCategories = PicoUtils.getParentCategories(name, category.pid); + const subCategories = PicoUtils.getSubCategories(name, catId); + const contents = PicoUtils.getCategoryContents(name, catId); + return ( +
    + + {Functions.mlang(category.title, lang)} - {Functions.mlang(pico.name, lang)} - {Functions.siteTitle(lang)} + + {pico.show_breadcrumbs !== 0 && ( +
    + {parentCategories.map((parentCategory: PicoCategoryData, idx: number) => { + const link = '/' + name + '/' + parentCategory.link; + return ( + + {idx > 0 && <> > } + {Functions.mlang(parentCategory.title, lang)} + + ); + })} + {parentCategories.length > 0 && <> > } + {Functions.mlang(category.title, lang)} +
    + )} + {catId === 0 && pico.message !== '' && ( +

    {Functions.mlang(pico.message, lang)}

    + )} +

    {Functions.mlang(category.title, lang)}

    + {category.desc !== '' && ( +

    {Functions.mlang(category.desc, lang)}

    + )} + {subCategories.length > 0 && ( + <> +

    {Functions.mlang('[en]Subcageroies[/en][ja]サブカテゴリー[/ja]', lang)}

    + {subCategories.map((subCategory: PicoCategoryData) => { + const url = '/' + name + '/' + subCategory.link; + return ( +
    +
    {Functions.mlang(subCategory.title, lang)}
    +
    {Functions.mlang(subCategory.desc, lang)}
    +
    + ); + })} + + )} + {contents.length > 0 && ( + <> +

    {Functions.mlang('[en]Contents[/en][ja]コンテンツ[/ja]', lang)}

    +
      + {contents.map((content: PicoContentData) => { + const url = '/' + name + '/' + content.link; + return
    • {Functions.mlang(content.title, lang)}
    • ; + })} +
    + + )} +
    + ); +}; + +export default PicoCategory; \ No newline at end of file diff --git a/src/pico/PicoContent.tsx b/src/pico/PicoContent.tsx new file mode 100644 index 0000000..522bbba --- /dev/null +++ b/src/pico/PicoContent.tsx @@ -0,0 +1,109 @@ +import React, { Component, Fragment } from 'react'; +import Helmet from 'react-helmet'; +import { Link } from 'react-router-dom'; +import { HashLink } from 'react-router-hash-link'; +import Loading from '../common/lib/Loading'; +import PageNotFound from '../common/lib/PageNotFound'; +import XoopsCode from '../common/lib/XoopsCode'; +import { MultiLang } from '../config'; +import Functions from '../functions'; +import PicoUtils, { PicoCategoryData, PicoPageData } from './lib/PicoUtils'; + +interface Props { + lang: MultiLang; + name: string; + contentId: number; +} + +interface State { + loading: boolean; + page: PicoPageData | null; +} + +class PicoContent extends Component { + + private isActive: boolean; + + constructor(props: Props) { + super(props); + this.state = { + loading: true, + page: null, + }; + this.isActive = false; + } + + componentDidMount() { + const { name, contentId } = this.props; + this.isActive = true; + this.updatePage(name, contentId); + } + + componentDidUpdate(prevProps: Props, prevState: State) { + const { name, contentId } = this.props; + const prevName = prevProps.name; + const prevContentId = prevProps.contentId; + if (name !== prevName || contentId !== prevContentId) { + this.setState({ loading: true, page: null }); + this.updatePage(name, contentId); + } + } + + componentWillUnmount() { + this.isActive = false; + } + + updatePage(name: string, contentId: number) { + this.isActive = true; + PicoUtils.getPage(name, contentId, (page: PicoPageData | null) => { + if (this.isActive) { + this.setState({ loading: false, page }); + } + }) + } + + render() { + const { lang, name, contentId } = this.props; + const { loading, page } = this.state; + if (loading) { + return ; + } + if (page === null) { + return ; + } + const pico = PicoUtils.getModule(name); + if (pico === null) { + return ; + } + const categories = PicoUtils.getContentCategery(name, contentId); + return ( +
    + + {Functions.mlang(page.title, lang)} - {Functions.mlang(pico.name, lang)} - {Functions.siteTitle(lang)} + + {pico.show_breadcrumbs !== 0 && ( +
    + {categories.map((category: PicoCategoryData, idx: number) => { + const link = '/' + name + '/' + category.link; + return ( + + {idx > 0 && <> > } + {Functions.mlang(category.title, lang)} + + ); + })} +  > {Functions.mlang(page.title, lang)} +
    + )} +
    + +
    +
    + {Functions.mlang('[en]Jump to the top[/en][ja]この記事の1行目に飛ぶ[/ja]', lang)} +
    +
    + ); + } +} + +export default PicoContent; diff --git a/src/pico/PicoIndex.tsx b/src/pico/PicoIndex.tsx new file mode 100644 index 0000000..2f8578d --- /dev/null +++ b/src/pico/PicoIndex.tsx @@ -0,0 +1,34 @@ +import React from 'react'; +import PageNotFound from '../common/lib/PageNotFound'; +import { MultiLang } from '../config'; +import PicoUtils from './lib/PicoUtils'; +import PicoCategory from './PicoCategory'; +import PicoContent from './PicoContent'; +import PicoMenu from './PicoMenu'; + +interface Props { + lang: MultiLang; + name: string; +} + +const PicoIndex = (props: Props) => { + const { lang, name } = props; + const pico = PicoUtils.getModule(name); + if (pico === null) { + return ; + } + if (pico.show_menuinmoduletop !== 0) { + return + } + if (pico.show_listasindex !== 0) { + return + } + const content = PicoUtils.getFirstContent(name, 0); + if (content === null) { + return ; + } + return ; + +} + +export default PicoIndex; diff --git a/src/pico/PicoMenu.tsx b/src/pico/PicoMenu.tsx new file mode 100644 index 0000000..05afc0c --- /dev/null +++ b/src/pico/PicoMenu.tsx @@ -0,0 +1,92 @@ +import React from 'react'; +import Helmet from 'react-helmet'; +import { Link } from 'react-router-dom'; +import PageNotFound from '../common/lib/PageNotFound'; +import { MultiLang } from '../config'; +import Functions from '../functions'; +import PicoUtils, { PicoCategoryData, PicoContentData } from './lib/PicoUtils'; + +interface Props { + lang: MultiLang; + name: string; +} + +interface PicoMenuCategoryProps { + lang: MultiLang; + name: string; + category: PicoCategoryData; + depth: number; +} + +const PicoMenuCategory = (props: PicoMenuCategoryProps) => { + const { lang, name, category, depth } = props; + const subCategories = PicoUtils.getSubCategories(name, category.id); + const contents = PicoUtils.getCategoryContents(name, category.id); + const level = 'level' + depth; + const link = {Functions.mlang(category.title, lang)}; + let title =
    {link}
    ; + switch (depth) { + case 1: + title =

    {link}

    ; + break; + case 2: + title =

    {link}

    ; + break; + case 3: + title =

    {link}

    ; + break; + case 4: + title =

    {link}

    ; + break; + case 5: + title =
    {link}
    ; + break; + } + return ( + <> + {title} + {contents.length > 0 && ( +
    +
      + {contents.map((content: PicoContentData) => { + const url = '/' + name + '/' + content.link; + return
    • {Functions.mlang(content.title, lang)}
    • ; + })} +
    +
    + )} + {subCategories.length > 0 && ( + <> + {subCategories.map((subCategory: PicoCategoryData) => { + return ; + })} + + )} + + ); +} + +const PicoMenu = (props: Props) => { + const { lang, name } = props; + const pico = PicoUtils.getModule(name); + if (pico === null) { + return ; + } + const category = PicoUtils.getCategory(name, 0); + if (category === null) { + return ; + } + return ( +
    + + {Functions.mlang('[en]Menu[/en][ja]メニュー[/ja]', lang)} - {Functions.mlang(pico.name, lang)} - {Functions.siteTitle(lang)} + + {pico.message !== '' && ( +

    {Functions.mlang(pico.message, lang)}

    + )} + +
    + ); +}; + +export default PicoMenu; \ No newline at end of file diff --git a/src/pico/PicoXoopsPathRedirect.tsx b/src/pico/PicoXoopsPathRedirect.tsx new file mode 100644 index 0000000..e39d888 --- /dev/null +++ b/src/pico/PicoXoopsPathRedirect.tsx @@ -0,0 +1,43 @@ +import React, { Component } from 'react'; +import { Redirect, RouteComponentProps, withRouter } from 'react-router'; +import PageNotFound from '../common/lib/PageNotFound'; +import { MultiLang } from '../config'; + +interface Props extends RouteComponentProps { + lang: MultiLang; + name: string; +} + +class PicoXoopsPathRedirect extends Component { + + getRedirectUrl(): string { + const { name, location } = this.props; + const pathname = location.pathname || ''; + const search = new RegExp(`^/modules/${name}(?:/+(.*))?$`); + const matches = pathname.match(search); + if (matches === null) { + return ''; + } + const path = matches[1] || ''; + switch (path) { + case '': + case 'index.php': { + const params = new URLSearchParams(location.search); + const paramString = params.toString(); + return '/' + name + '/' + (paramString !== '' ? '?' + paramString : ''); + } + } + return '/' + name + '/' + path; + } + + render() { + const { lang } = this.props; + const url = this.getRedirectUrl(); + if (url === '') { + return ; + } + return ; + } +} + +export default withRouter(PicoXoopsPathRedirect); diff --git a/src/pico/assets/pico_main.css b/src/pico/assets/pico_main.css new file mode 100644 index 0000000..9413c22 --- /dev/null +++ b/src/pico/assets/pico_main.css @@ -0,0 +1,140 @@ +div.pico_breadcrumbs { + font-size: 95%; + padding: 0 0 3px; + border-bottom: 1px #aaa solid; +} + +.pico_body { + margin: 0 -2px; + padding: 15px 8px; +} + +div.pico_menu h1 { + margin: 18px 0 0 0; + padding: 3px; + background-color: #eee; +} +div.pico_menu h2 { + margin: 18px 0 0 10px; + padding: 3px; + background-color: #eee; +} +div.pico_menu h3 { + margin: 18px 0 0 20px; + padding: 3px; + background-color: #eee; +} +div.pico_menu h4 { + margin: 18px 0 0 30px; + padding: 3px; + background-color: #eee; +} +div.pico_menu h5 { + margin: 18px 0 0 40px; + padding: 3px; + background-color: #eee; +} +div.pico_menu div.level1 { + margin-left: 0; +} +div.pico_menu div.level2 { + margin-left: 10px; +} +div.pico_menu div.level3 { + margin-left: 20px; +} +div.pico_menu div.level4 { + margin-left: 30px; +} +div.pico_menu div.level5 { + margin-left: 40px; +} + +em.pico_notice { + font-weight: bold; + font-style: normal; + color: #ff0000; +} + +div.pico_controllers_in_menu { + float: right; + position: relative; + top: -1.5em; +} + +div.bottom_of_content_body { + clear: right; +} + +ul.pico_list_contents li { + list-style: none outside; +} +ul.pico_list_contents_in_menu li { + list-style: none outside; +} + +div.pico_print_icon { + float: right; + width: 40px; + height: 40px; +} +div.pico_tellafriend_icon { + float: right; + width: 40px; + height: 40px; +} +div.pico_vote form { + display: inline; +} + +table.pico_pagenavigation { + border-top: 1px #aaa solid; + margin-top: 20px; +} + +table.pico_form_table th.pico_waiting { + color: red; +} +table.pico_form_table td.pico_waiting { + color: red; + background-color: white; +} + +table.pico_form_table td, +table.pico_form_table th { + color: black; + vertical-align: top !important; + text-align: left; +} +p.pico_submit { + text-align: center; + margin: 0; + padding: 10px; +} + +input.pico_ascii_only { + ime-mode: disabled; +} +input.pico_number_only { + ime-mode: disabled; + text-align: right; +} + +pre.pico_history_diff del { + color: red; +} +pre.pico_history_diff ins { + color: blue; +} + +div.pico_pagebreak { + margin: 10px; +} +div.pico_pagebreak span { + border: 1px solid black; + padding: 2px; + margin: 2px; +} +div.pico_pagebreak span.selected { + border: 0px; +} diff --git a/src/pico/lib/PicoUtils.ts b/src/pico/lib/PicoUtils.ts new file mode 100644 index 0000000..c33f876 --- /dev/null +++ b/src/pico/lib/PicoUtils.ts @@ -0,0 +1,180 @@ +import axios from 'axios'; +import loki from 'lokijs'; +import configJson from '../assets/config.json'; + +export interface PicoModuleData { + name: string; + dirname: string; + message: string; + show_menuinmoduletop: number; + show_listasindex: number; + show_breadcrumbs: number; + show_pagenavi: number; +} + +export interface PicoCategoryData { + id: number; + title: string; + desc: string; + pid: number; + weight: number; + link: string; +} + +export interface PicoContentData { + id: number; + title: string; + cat_id: number; + weight: number; + link: string; +} + +interface PicoConfigData { + module: PicoModuleData; + categories: PicoCategoryData[]; + contents: PicoContentData[]; +} + +interface PicoData { + module: PicoModuleData; + categories: Collection; + contents: Collection; +} + +export interface PicoPageData { + id: number; + title: string; + content: string; +} + +export const PICO_CATEGORY_ID_ROOT = 65535; +export type GetPageCallback = (page: PicoPageData | null) => void; + +class PicoUtils { + + private database: loki; + private modules: Map; + + constructor(json: PicoConfigData[]) { + this.database = new loki('pico'); + this.modules = new Map(); + json.forEach((data) => { + const name = data.module.dirname; + const pico = { + module: data.module, + categories: this.database.addCollection(name + '_categories'), + contents: this.database.addCollection(name + '_contents'), + }; + data.categories.forEach(category => { + pico.categories.insert(category); + }); + data.contents.forEach(content => { + pico.contents.insert(content); + }); + this.modules.set(name, pico); + }) + } + + getModule(name: string): PicoModuleData | null { + const pico = this.modules.get(name); + if (typeof pico === 'undefined') { + return null; + } + return pico.module; + } + + getCategoryByPath(name: string, link: string): PicoCategoryData | null { + const pico = this.modules.get(name); + if (typeof pico === 'undefined') { + return null; + } + const content = pico.categories.findOne({ link: link }); + return content; + } + + getCategory(name: string, catId: number): PicoCategoryData | null { + const pico = this.modules.get(name); + if (typeof pico === 'undefined') { + return null; + } + const category = pico.categories.findOne({ id: catId }); + return category; + } + + getParentCategories(name: string, catId: number): PicoCategoryData[] { + const categories: PicoCategoryData[] = []; + const pico = this.modules.get(name); + if (typeof pico === 'undefined') { + return categories; + } + while (catId !== PICO_CATEGORY_ID_ROOT) { + const category = pico.categories.findOne({ id: catId }); + if (category === null) { + break; + } + categories.unshift(category); + catId = category.pid; + } + return categories; + } + + getSubCategories(name: string, catId: number): PicoCategoryData[] { + const pico = this.modules.get(name); + if (typeof pico === 'undefined') { + return []; + } + return pico.categories.chain().find({ pid: catId }).simplesort('weight').data(); + } + + getCategoryContents(name: string, catId: number): PicoContentData[] { + const pico = this.modules.get(name); + if (typeof pico === 'undefined') { + return []; + } + return pico.contents.chain().find({ cat_id: catId }).simplesort('weight').data(); + } + + getContentCategery(name: string, contentId: number): PicoCategoryData[] { + const pico = this.modules.get(name); + if (typeof pico === 'undefined') { + return []; + } + const content = pico.contents.findOne({ id: contentId }); + if (content === null) { + return []; + } + return this.getParentCategories(name, content.cat_id); + } + + getFirstContent(name: string, catId: number): PicoContentData | null { + const pico = this.modules.get(name); + if (typeof pico === 'undefined') { + return null; + } + const contents = pico.contents.chain().find({ cat_id: catId }).simplesort('weight').limit(1).data(); + if (contents.length !== 1) { + return null; + } + return contents[0]; + } + + getContentByPath(name: string, link: string): PicoContentData | null { + const pico = this.modules.get(name); + if (typeof pico === 'undefined') { + return null; + } + const content = pico.contents.findOne({ link: link }); + return content as PicoContentData | null; + } + + getPage(name: string, contentId: number, callback: GetPageCallback): void { + axios.get('/' + name + '/' + contentId + '.json').then((response) => { + const page = response.data as PicoPageData; + callback(page); + }).catch(e => { + callback(null); + }); + } +} + +export default new PicoUtils(configJson); \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 0a348e3..dce2903 100644 --- a/yarn.lock +++ b/yarn.lock @@ -756,7 +756,15 @@ "@babel/helper-plugin-utils" "^7.0.0" "@babel/plugin-transform-typescript" "^7.3.2" -"@babel/runtime@7.5.5", "@babel/runtime@^7.0.0", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.5": +"@babel/runtime-corejs2@^7.2.0": + version "7.5.5" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs2/-/runtime-corejs2-7.5.5.tgz#c3214c08ef20341af4187f1c9fbdc357fbec96b2" + integrity sha512-FYATQVR00NSNi7mUfpPDp7E8RYMXDuO8gaix7u/w3GekfUinKgX1AcTxs7SoiEmoEW9mbpjrwqWSW6zCmw5h8A== + dependencies: + core-js "^2.6.5" + regenerator-runtime "^0.13.2" + +"@babel/runtime@7.5.5", "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.2", "@babel/runtime@^7.4.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.5.tgz#74fba56d35efbeca444091c7850ccd494fd2f132" integrity sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ== @@ -819,10 +827,10 @@ resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.0.0.tgz#9f05469c88cb2fd3dcd624776b54ee95c312126a" integrity sha512-mV6T0IYqb0xL1UALPFplXYQmR0twnXG0M6jUswpquqT2sD12BOiCiLy3EvMp/Fy7s3DZElC4/aPjEjo2jeZpvw== -"@hapi/hoek@6.x.x": - version "6.2.4" - resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-6.2.4.tgz#4b95fbaccbfba90185690890bdf1a2fbbda10595" - integrity sha512-HOJ20Kc93DkDVvjwHyHawPwPkX44sIrbXazAUDiUXaY2R9JwQGo2PhFfnQtdrsIe4igjG2fPgMra7NYw7qhy0A== +"@hapi/bourne@1.x.x": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-1.3.2.tgz#0a7095adea067243ce3283e1b56b8a8f453b242a" + integrity sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA== "@hapi/hoek@8.x.x": version "8.2.1" @@ -830,20 +838,15 @@ integrity sha512-JPiBy+oSmsq3St7XlipfN5pNA6bDJ1kpa73PrK/zR29CVClDVqy04AanM/M/qx5bSF+I61DdCfAvRrujau+zRg== "@hapi/joi@^15.0.0": - version "15.1.0" - resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.1.0.tgz#940cb749b5c55c26ab3b34ce362e82b6162c8e7a" - integrity sha512-n6kaRQO8S+kepUTbXL9O/UOL788Odqs38/VOfoCrATDtTvyfiO3fgjlSRaNkHabpTLgM7qru9ifqXlXbXk8SeQ== + version "15.1.1" + resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.1.1.tgz#c675b8a71296f02833f8d6d243b34c57b8ce19d7" + integrity sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ== dependencies: "@hapi/address" "2.x.x" - "@hapi/hoek" "6.x.x" - "@hapi/marker" "1.x.x" + "@hapi/bourne" "1.x.x" + "@hapi/hoek" "8.x.x" "@hapi/topo" "3.x.x" -"@hapi/marker@1.x.x": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@hapi/marker/-/marker-1.0.0.tgz#65b0b2b01d1be06304886ce9b4b77b1bfb21a769" - integrity sha512-JOfdekTXnJexfE8PyhZFyHvHjt81rBFSAbTIRAhF2vv/2Y1JzoKsGqxH/GpZJoF7aEfYok8JVcAHmSz1gkBieA== - "@hapi/topo@3.x.x": version "3.1.3" resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-3.1.3.tgz#c7a02e0d936596d29f184e6d7fdc07e8b5efce11" @@ -851,76 +854,77 @@ dependencies: "@hapi/hoek" "8.x.x" -"@jest/console@^24.7.1": - version "24.7.1" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.7.1.tgz#32a9e42535a97aedfe037e725bd67e954b459545" - integrity sha512-iNhtIy2M8bXlAOULWVTUxmnelTLFneTNEkHCgPmgd+zNwy9zVddJ6oS5rZ9iwoscNdT5mMwUd0C51v/fSlzItg== +"@jest/console@^24.7.1", "@jest/console@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.9.0.tgz#79b1bc06fb74a8cfb01cbdedf945584b1b9707f0" + integrity sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ== dependencies: - "@jest/source-map" "^24.3.0" + "@jest/source-map" "^24.9.0" chalk "^2.0.1" slash "^2.0.0" -"@jest/core@^24.8.0": - version "24.8.0" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-24.8.0.tgz#fbbdcd42a41d0d39cddbc9f520c8bab0c33eed5b" - integrity sha512-R9rhAJwCBQzaRnrRgAdVfnglUuATXdwTRsYqs6NMdVcAl5euG8LtWDe+fVkN27YfKVBW61IojVsXKaOmSnqd/A== +"@jest/core@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-24.9.0.tgz#2ceccd0b93181f9c4850e74f2a9ad43d351369c4" + integrity sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A== dependencies: "@jest/console" "^24.7.1" - "@jest/reporters" "^24.8.0" - "@jest/test-result" "^24.8.0" - "@jest/transform" "^24.8.0" - "@jest/types" "^24.8.0" + "@jest/reporters" "^24.9.0" + "@jest/test-result" "^24.9.0" + "@jest/transform" "^24.9.0" + "@jest/types" "^24.9.0" ansi-escapes "^3.0.0" chalk "^2.0.1" exit "^0.1.2" graceful-fs "^4.1.15" - jest-changed-files "^24.8.0" - jest-config "^24.8.0" - jest-haste-map "^24.8.0" - jest-message-util "^24.8.0" + jest-changed-files "^24.9.0" + jest-config "^24.9.0" + jest-haste-map "^24.9.0" + jest-message-util "^24.9.0" jest-regex-util "^24.3.0" - jest-resolve-dependencies "^24.8.0" - jest-runner "^24.8.0" - jest-runtime "^24.8.0" - jest-snapshot "^24.8.0" - jest-util "^24.8.0" - jest-validate "^24.8.0" - jest-watcher "^24.8.0" + jest-resolve "^24.9.0" + jest-resolve-dependencies "^24.9.0" + jest-runner "^24.9.0" + jest-runtime "^24.9.0" + jest-snapshot "^24.9.0" + jest-util "^24.9.0" + jest-validate "^24.9.0" + jest-watcher "^24.9.0" micromatch "^3.1.10" p-each-series "^1.0.0" - pirates "^4.0.1" realpath-native "^1.1.0" rimraf "^2.5.4" + slash "^2.0.0" strip-ansi "^5.0.0" -"@jest/environment@^24.8.0": - version "24.8.0" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-24.8.0.tgz#0342261383c776bdd652168f68065ef144af0eac" - integrity sha512-vlGt2HLg7qM+vtBrSkjDxk9K0YtRBi7HfRFaDxoRtyi+DyVChzhF20duvpdAnKVBV6W5tym8jm0U9EfXbDk1tw== +"@jest/environment@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-24.9.0.tgz#21e3afa2d65c0586cbd6cbefe208bafade44ab18" + integrity sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ== dependencies: - "@jest/fake-timers" "^24.8.0" - "@jest/transform" "^24.8.0" - "@jest/types" "^24.8.0" - jest-mock "^24.8.0" + "@jest/fake-timers" "^24.9.0" + "@jest/transform" "^24.9.0" + "@jest/types" "^24.9.0" + jest-mock "^24.9.0" -"@jest/fake-timers@^24.8.0": - version "24.8.0" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-24.8.0.tgz#2e5b80a4f78f284bcb4bd5714b8e10dd36a8d3d1" - integrity sha512-2M4d5MufVXwi6VzZhJ9f5S/wU4ud2ck0kxPof1Iz3zWx6Y+V2eJrES9jEktB6O3o/oEyk+il/uNu9PvASjWXQw== +"@jest/fake-timers@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-24.9.0.tgz#ba3e6bf0eecd09a636049896434d306636540c93" + integrity sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A== dependencies: - "@jest/types" "^24.8.0" - jest-message-util "^24.8.0" - jest-mock "^24.8.0" + "@jest/types" "^24.9.0" + jest-message-util "^24.9.0" + jest-mock "^24.9.0" -"@jest/reporters@^24.8.0": - version "24.8.0" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-24.8.0.tgz#075169cd029bddec54b8f2c0fc489fd0b9e05729" - integrity sha512-eZ9TyUYpyIIXfYCrw0UHUWUvE35vx5I92HGMgS93Pv7du+GHIzl+/vh8Qj9MCWFK/4TqyttVBPakWMOfZRIfxw== +"@jest/reporters@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-24.9.0.tgz#86660eff8e2b9661d042a8e98a028b8d631a5b43" + integrity sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw== dependencies: - "@jest/environment" "^24.8.0" - "@jest/test-result" "^24.8.0" - "@jest/transform" "^24.8.0" - "@jest/types" "^24.8.0" + "@jest/environment" "^24.9.0" + "@jest/test-result" "^24.9.0" + "@jest/transform" "^24.9.0" + "@jest/types" "^24.9.0" chalk "^2.0.1" exit "^0.1.2" glob "^7.1.2" @@ -928,74 +932,75 @@ istanbul-lib-instrument "^3.0.1" istanbul-lib-report "^2.0.4" istanbul-lib-source-maps "^3.0.1" - istanbul-reports "^2.1.1" - jest-haste-map "^24.8.0" - jest-resolve "^24.8.0" - jest-runtime "^24.8.0" - jest-util "^24.8.0" + istanbul-reports "^2.2.6" + jest-haste-map "^24.9.0" + jest-resolve "^24.9.0" + jest-runtime "^24.9.0" + jest-util "^24.9.0" jest-worker "^24.6.0" - node-notifier "^5.2.1" + node-notifier "^5.4.2" slash "^2.0.0" source-map "^0.6.0" string-length "^2.0.0" -"@jest/source-map@^24.3.0": - version "24.3.0" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-24.3.0.tgz#563be3aa4d224caf65ff77edc95cd1ca4da67f28" - integrity sha512-zALZt1t2ou8le/crCeeiRYzvdnTzaIlpOWaet45lNSqNJUnXbppUUFR4ZUAlzgDmKee4Q5P/tKXypI1RiHwgag== +"@jest/source-map@^24.3.0", "@jest/source-map@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-24.9.0.tgz#0e263a94430be4b41da683ccc1e6bffe2a191714" + integrity sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg== dependencies: callsites "^3.0.0" graceful-fs "^4.1.15" source-map "^0.6.0" -"@jest/test-result@^24.8.0": - version "24.8.0" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-24.8.0.tgz#7675d0aaf9d2484caa65e048d9b467d160f8e9d3" - integrity sha512-+YdLlxwizlfqkFDh7Mc7ONPQAhA4YylU1s529vVM1rsf67vGZH/2GGm5uO8QzPeVyaVMobCQ7FTxl38QrKRlng== +"@jest/test-result@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-24.9.0.tgz#11796e8aa9dbf88ea025757b3152595ad06ba0ca" + integrity sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA== dependencies: - "@jest/console" "^24.7.1" - "@jest/types" "^24.8.0" + "@jest/console" "^24.9.0" + "@jest/types" "^24.9.0" "@types/istanbul-lib-coverage" "^2.0.0" -"@jest/test-sequencer@^24.8.0": - version "24.8.0" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-24.8.0.tgz#2f993bcf6ef5eb4e65e8233a95a3320248cf994b" - integrity sha512-OzL/2yHyPdCHXEzhoBuq37CE99nkme15eHkAzXRVqthreWZamEMA0WoetwstsQBCXABhczpK03JNbc4L01vvLg== +"@jest/test-sequencer@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz#f8f334f35b625a4f2f355f2fe7e6036dad2e6b31" + integrity sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A== dependencies: - "@jest/test-result" "^24.8.0" - jest-haste-map "^24.8.0" - jest-runner "^24.8.0" - jest-runtime "^24.8.0" + "@jest/test-result" "^24.9.0" + jest-haste-map "^24.9.0" + jest-runner "^24.9.0" + jest-runtime "^24.9.0" -"@jest/transform@^24.8.0": - version "24.8.0" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-24.8.0.tgz#628fb99dce4f9d254c6fd9341e3eea262e06fef5" - integrity sha512-xBMfFUP7TortCs0O+Xtez2W7Zu1PLH9bvJgtraN1CDST6LBM/eTOZ9SfwS/lvV8yOfcDpFmwf9bq5cYbXvqsvA== +"@jest/transform@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-24.9.0.tgz#4ae2768b296553fadab09e9ec119543c90b16c56" + integrity sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ== dependencies: "@babel/core" "^7.1.0" - "@jest/types" "^24.8.0" + "@jest/types" "^24.9.0" babel-plugin-istanbul "^5.1.0" chalk "^2.0.1" convert-source-map "^1.4.0" fast-json-stable-stringify "^2.0.0" graceful-fs "^4.1.15" - jest-haste-map "^24.8.0" - jest-regex-util "^24.3.0" - jest-util "^24.8.0" + jest-haste-map "^24.9.0" + jest-regex-util "^24.9.0" + jest-util "^24.9.0" micromatch "^3.1.10" + pirates "^4.0.1" realpath-native "^1.1.0" slash "^2.0.0" source-map "^0.6.1" write-file-atomic "2.4.1" -"@jest/types@^24.8.0": - version "24.8.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.8.0.tgz#f31e25948c58f0abd8c845ae26fcea1491dea7ad" - integrity sha512-g17UxVr2YfBtaMUxn9u/4+siG1ptg9IGYAYwvpwn61nBg779RXnjE/m7CxYcIzEt0AbHZZAHSEZNhkE2WxURVg== +"@jest/types@^24.8.0", "@jest/types@^24.9.0": + version "24.9.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" + integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== dependencies: "@types/istanbul-lib-coverage" "^2.0.0" "@types/istanbul-reports" "^1.1.1" - "@types/yargs" "^12.0.9" + "@types/yargs" "^13.0.0" "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" @@ -1113,6 +1118,11 @@ "@svgr/plugin-svgo" "^4.3.1" loader-utils "^1.2.3" +"@types/async-lock@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@types/async-lock/-/async-lock-1.1.1.tgz#81f218213bebcc5f740efe9648272c774a2e4b4b" + integrity sha512-TU1X8jmAU2BjwKryBFV/GDezz7Ge0xu9ZuYC7dy6wKj4hnL0JcxeseCOr/G2JkGylff6hdUBrR+Ee5ApAQeU5g== + "@types/babel__core@^7.1.0": version "7.1.2" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.2.tgz#608c74f55928033fce18b99b213c16be4b3d114f" @@ -1146,11 +1156,50 @@ dependencies: "@babel/types" "^7.3.0" +"@types/cookie@^0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.3.3.tgz#85bc74ba782fb7aa3a514d11767832b0e3bc6803" + integrity sha512-LKVP3cgXBT9RYj+t+9FDKwS5tdI+rPBXaNSkma7hvqy35lc7mAokC2zsqWJH0LaqIt3B962nuYI77hsJoT1gow== + +"@types/domhandler@*": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@types/domhandler/-/domhandler-2.4.1.tgz#7b3b347f7762180fbcb1ece1ce3dd0ebbb8c64cf" + integrity sha512-cfBw6q6tT5sa1gSPFSRKzF/xxYrrmeiut7E0TxNBObiLSBTuFEHibcfEe3waQPEDbqBsq+ql/TOniw65EyDFMA== + +"@types/domutils@*": + version "1.7.2" + resolved "https://registry.yarnpkg.com/@types/domutils/-/domutils-1.7.2.tgz#89422e579c165994ad5c09ce90325da596cc105d" + integrity sha512-Nnwy1Ztwq42SSNSZSh9EXBJGrOZPR+PQ2sRT4VZy8hnsFXfCil7YlKO2hd2360HyrtFz2qwnKQ13ENrgXNxJbw== + dependencies: + "@types/domhandler" "*" + "@types/eslint-visitor-keys@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== +"@types/history@*": + version "4.7.3" + resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.3.tgz#856c99cdc1551d22c22b18b5402719affec9839a" + integrity sha512-cS5owqtwzLN5kY+l+KgKdRJ/Cee8tlmQoGQuIE9tWnSmS3JMKzmxo2HIAk2wODMifGwO20d62xZQLYz+RLfXmw== + +"@types/hoist-non-react-statics@^3.0.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" + integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== + dependencies: + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + +"@types/htmlparser2@*": + version "3.10.1" + resolved "https://registry.yarnpkg.com/@types/htmlparser2/-/htmlparser2-3.10.1.tgz#1e65ba81401d53f425c1e2ba5a3d05c90ab742c7" + integrity sha512-fCxmHS4ryCUCfV9+CJZY1UjkbR+6Al/EQdX5Jh03qBj9gdlPG5q+7uNoDgE/ZNXb3XNWSAQgqKIWnbRCbOyyWA== + dependencies: + "@types/domhandler" "*" + "@types/domutils" "*" + "@types/node" "*" + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff" @@ -1176,10 +1225,10 @@ resolved "https://registry.yarnpkg.com/@types/jest-diff/-/jest-diff-20.0.1.tgz#35cc15b9c4f30a18ef21852e255fdb02f6d59b89" integrity sha512-yALhelO3i0hqZwhjtcr6dYyaLoCHbAMshwtj6cGxTvHZAKXHsYGdff6E8EPw3xLKY0ELUTQ69Q1rQiJENnccMA== -"@types/jest@24.0.17": - version "24.0.17" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.0.17.tgz#b66ea026efb746eb5db1356ee28518aaff7af416" - integrity sha512-1cy3xkOAfSYn78dsBWy4M3h/QF/HeWPchNFDjysVtp3GHeTdSmtluNnELfCmfNRRHo0OWEcpf+NsEJQvwQfdqQ== +"@types/jest@24.0.18": + version "24.0.18" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.0.18.tgz#9c7858d450c59e2164a8a9df0905fc5091944498" + integrity sha512-jcDDXdjTcrQzdN06+TSVsPPqxvsZA/5QkYfIZlq1JMw7FdP5AZylbOc+6B/cuDurctRe+MziUMtQ3xQdrbjqyQ== dependencies: "@types/jest-diff" "*" @@ -1188,11 +1237,21 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.3.tgz#bdfd69d61e464dcc81b25159c270d75a73c1a636" integrity sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A== -"@types/node@12.7.2": +"@types/lokijs@^1.5.2": + version "1.5.2" + resolved "https://registry.yarnpkg.com/@types/lokijs/-/lokijs-1.5.2.tgz#ed228f080033ce1fb16eff4acde65cb9ae0f1bf2" + integrity sha512-ZF14v1P1Bjbw8VJRu+p4WS9V926CAOjWF4yq23QmSBWRPe0/GXlUKzSxjP1fi/xi8nrq6zr9ECo8Z/8KsRqroQ== + +"@types/node@*", "@types/node@12.7.2": version "12.7.2" resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.2.tgz#c4e63af5e8823ce9cc3f0b34f7b998c2171f0c44" integrity sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg== +"@types/object-assign@^4.0.30": + version "4.0.30" + resolved "https://registry.yarnpkg.com/@types/object-assign/-/object-assign-4.0.30.tgz#8949371d5a99f4381ee0f1df0a9b7a187e07e652" + integrity sha1-iUk3HVqZ9Dge4PHfCpt6GH4H5lI= + "@types/prop-types@*": version "15.7.1" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.1.tgz#f1a11e7babb0c3cad68100be381d1e064c68f1f6" @@ -1203,10 +1262,65 @@ resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" integrity sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw== -"@types/react-dom@16.8.5": - version "16.8.5" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.8.5.tgz#3e3f4d99199391a7fb40aa3a155c8dd99b899cbd" - integrity sha512-idCEjROZ2cqh29+trmTmZhsBAUNQuYrF92JHKzZ5+aiFM1mlSk3bb23CK7HhYuOY75Apgap5y2jTyHzaM2AJGA== +"@types/react-dom@16.9.0": + version "16.9.0" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.0.tgz#ba6ddb00bf5de700b0eb91daa452081ffccbfdea" + integrity sha512-OL2lk7LYGjxn4b0efW3Pvf2KBVP0y1v3wip1Bp7nA79NkOpElH98q3WdCEdDj93b2b0zaeBG9DvriuKjIK5xDA== + dependencies: + "@types/react" "*" + +"@types/react-helmet@^5.0.9": + version "5.0.9" + resolved "https://registry.yarnpkg.com/@types/react-helmet/-/react-helmet-5.0.9.tgz#60ab5accce74b168ca1d274671522f6b2cf2c98f" + integrity sha512-0UVaMQk/Xvq6rFaGyepSBnRApy5RE+YH0XAXlbOBhtez5D9y1/jxKaKODofPzNnJLoLQ+sATTsWQIvrw1Dtiag== + dependencies: + "@types/react" "*" + +"@types/react-html-parser@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/react-html-parser/-/react-html-parser-2.0.1.tgz#2d9002ac5bf1adf9aff8eae77ace5488bd78c98d" + integrity sha512-Lyw0AtG3gahw78CX2pzmzhKaoZCfJNzzuhhPsFVhzFrylMv8NaCmzYaPKglMv3RRHpwBbHuMOkVx0HiwGZKgSA== + dependencies: + "@types/htmlparser2" "*" + "@types/react" "*" + +"@types/react-overlays@^1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@types/react-overlays/-/react-overlays-1.1.3.tgz#fb97081cbf506917e358f0523b34fed14e2de2f7" + integrity sha512-oOq5NWbyfNz2w2sKvjkHdvGQSMA+VDVfI5UOfGPR0wkik2welad1RDVnVgH15jKf58jrZNBa1Ee4SVBgCGFxCg== + dependencies: + "@types/react" "*" + "@types/react-transition-group" "*" + +"@types/react-router-dom@*", "@types/react-router-dom@^4.3.5": + version "4.3.5" + resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-4.3.5.tgz#72f229967690c890d00f96e6b85e9ee5780db31f" + integrity sha512-eFajSUASYbPHg2BDM1G8Btx+YqGgvROPIg6sBhl3O4kbDdYXdFdfrgQFf/pcBuQVObjfT9AL/dd15jilR5DIEA== + dependencies: + "@types/history" "*" + "@types/react" "*" + "@types/react-router" "*" + +"@types/react-router-hash-link@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@types/react-router-hash-link/-/react-router-hash-link-1.2.1.tgz#fba7dc351cef2985791023018b7a5dbd0653c843" + integrity sha512-jdzPGE8jFGq7fHUpPaKrJvLW1Yhoe5MQCrmgeesC+eSLseMj3cGCTYMDA4BNWG8JQmwO8NTYt/oT3uBZ77pmBA== + dependencies: + "@types/react" "*" + "@types/react-router-dom" "*" + +"@types/react-router@*": + version "5.0.3" + resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.0.3.tgz#855a1606e62de3f4d69ea34fb3c0e50e98e964d5" + integrity sha512-j2Gge5cvxca+5lK9wxovmGPgpVJMwjyu5lTA/Cd6fLGoPq7FXcUE1jFkEdxeyqGGz8VfHYSHCn5Lcn24BzaNKA== + dependencies: + "@types/history" "*" + "@types/react" "*" + +"@types/react-transition-group@*": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.2.2.tgz#8c851c4598a23a3a34173069fb4c5c9e41c02e3f" + integrity sha512-YfoaTNqBwbIqpiJ5NNfxfgg5kyFP1Hqf/jqBtSWNv0E+EkkxmN+3VD6U2fu86tlQvdAc1o0SdWhnWFwcRMTn9A== dependencies: "@types/react" "*" @@ -1223,10 +1337,22 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== -"@types/yargs@^12.0.2", "@types/yargs@^12.0.9": - version "12.0.12" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-12.0.12.tgz#45dd1d0638e8c8f153e87d296907659296873916" - integrity sha512-SOhuU4wNBxhhTHxYaiG5NY4HBhDIDnJF60GU+2LqHAdKKer86//e4yg69aENCtQ04n0ovz+tq2YPME5t5yp4pw== +"@types/xregexp@^3.0.30": + version "3.0.30" + resolved "https://registry.yarnpkg.com/@types/xregexp/-/xregexp-3.0.30.tgz#333d550467dd27ef989f375629f8f279a97cee39" + integrity sha512-u1dpabg81Rd660bYebOqMXO0+E63H1hxunPAWGebNb7TpxqZYe9YaVLgkkj6ZnzLs3yLumtVB956o8u8OZdhXw== + +"@types/yargs-parser@*": + version "13.0.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-13.0.0.tgz#453743c5bbf9f1bed61d959baab5b06be029b2d0" + integrity sha512-wBlsw+8n21e6eTd4yVv8YD/E3xq0O6nNnJIquutAsFGE7EyMKz7W6RNT6BRu1SmdgmlCZ9tb0X+j+D6HGr8pZw== + +"@types/yargs@^13.0.0": + version "13.0.2" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.2.tgz#a64674fc0149574ecd90ba746e932b5a5f7b3653" + integrity sha512-lwwgizwk/bIIU+3ELORkyuOgDjCh7zuWDFqRtPPhhVgq9N1F7CvLNKg1TX4f2duwtKQ0p044Au9r1PLIXHrIzQ== + dependencies: + "@types/yargs-parser" "*" "@typescript-eslint/eslint-plugin@1.13.0": version "1.13.0" @@ -1448,10 +1574,10 @@ acorn-globals@^4.1.0, acorn-globals@^4.3.0: acorn "^6.0.1" acorn-walk "^6.0.1" -acorn-jsx@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e" - integrity sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg== +acorn-jsx@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.2.tgz#84b68ea44b373c4f8686023a551f61a21b7c4a4f" + integrity sha512-tiNTrP1MP0QrChmD2DdupCr6HWSFeKVw5d/dHTu4Y7rkAkRhU/Dt7dphAfIUyxtHpl/eBVip5uTNSpQJHylpAw== acorn-walk@^6.0.1: version "6.2.0" @@ -1463,16 +1589,33 @@ acorn@^5.5.3: resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== -acorn@^6.0.1, acorn@^6.0.4, acorn@^6.0.7, acorn@^6.2.1: +acorn@^6.0.1, acorn@^6.0.4, acorn@^6.2.1: version "6.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.3.0.tgz#0087509119ffa4fc0a0041d1e93a417e68cb856e" integrity sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA== -address@1.1.0, address@^1.0.1: +acorn@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.0.0.tgz#26b8d1cd9a9b700350b71c0905546f64d1284e7a" + integrity sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ== + +add-dom-event-listener@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz#6a92db3a0dd0abc254e095c0f1dc14acbbaae310" + integrity sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw== + dependencies: + object-assign "4.x" + +address@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/address/-/address-1.1.0.tgz#ef8e047847fcd2c5b6f50c16965f924fd99fe709" integrity sha512-4diPfzWbLEIElVG4AnqP+00SULlPzNuyJFNnmMrLgyaxG6tZXJ1sn7mjBu4fHrJE+Yp/jgylOweJn2xsLMFggQ== +address@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" + integrity sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA== + adjust-sourcemap-loader@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/adjust-sourcemap-loader/-/adjust-sourcemap-loader-2.0.0.tgz#6471143af75ec02334b219f54bc7970c52fb29a4" @@ -1519,13 +1662,6 @@ ansi-escapes@^3.0.0, ansi-escapes@^3.2.0: resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== -ansi-escapes@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.2.1.tgz#4dccdb846c3eee10f6d64dea66273eab90c37228" - integrity sha512-Cg3ymMAdN10wOk/VYfLV7KCQyv7EDirJ64500sU7n9UlmioEtDuU5Gd+hj73hXSU/ex7tHJSssmyftDdkMLO8Q== - dependencies: - type-fest "^0.5.2" - ansi-html@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" @@ -1674,7 +1810,7 @@ arrify@^1.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= -asap@~2.0.6: +asap@~2.0.3, asap@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= @@ -1740,6 +1876,11 @@ async-limiter@~1.0.0: resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== +async-lock@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/async-lock/-/async-lock-1.2.2.tgz#480bd51e4b7ffd4debbd4973763718ec9acb9a9e" + integrity sha512-uczz62z2fMWOFbyo6rG4NlV2SdxugJT6sZA2QcfB1XaSjEiOh8CuOb/TttyMnYQCda6nkWecJe465tGQDPJiKw== + async@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" @@ -1778,6 +1919,14 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== +axios@^0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.0.tgz#8e09bff3d9122e133f7b8101c8fbdd00ed3d2ab8" + integrity sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ== + dependencies: + follow-redirects "1.5.10" + is-buffer "^2.0.2" + axobject-query@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.0.2.tgz#ea187abe5b9002b377f925d8bf7d1c561adf38f9" @@ -1813,16 +1962,16 @@ babel-extract-comments@^1.0.0: dependencies: babylon "^6.18.0" -babel-jest@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.8.0.tgz#5c15ff2b28e20b0f45df43fe6b7f2aae93dba589" - integrity sha512-+5/kaZt4I9efoXzPlZASyK/lN9qdRKmmUav9smVc0ruPQD7IsfucQ87gpOE8mn2jbDuS6M/YOW6n3v9ZoIfgnw== +babel-jest@^24.8.0, babel-jest@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.9.0.tgz#3fc327cb8467b89d14d7bc70e315104a783ccd54" + integrity sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw== dependencies: - "@jest/transform" "^24.8.0" - "@jest/types" "^24.8.0" + "@jest/transform" "^24.9.0" + "@jest/types" "^24.9.0" "@types/babel__core" "^7.1.0" babel-plugin-istanbul "^5.1.0" - babel-preset-jest "^24.6.0" + babel-preset-jest "^24.9.0" chalk "^2.4.2" slash "^2.0.0" @@ -1853,10 +2002,10 @@ babel-plugin-istanbul@^5.1.0: istanbul-lib-instrument "^3.3.0" test-exclude "^5.2.3" -babel-plugin-jest-hoist@^24.6.0: - version "24.6.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.6.0.tgz#f7f7f7ad150ee96d7a5e8e2c5da8319579e78019" - integrity sha512-3pKNH6hMt9SbOv0F3WVmy5CWQ4uogS3k0GY5XLyQHJ9EGpAT9XWkFd2ZiXXtkwFHdAHa5j7w7kfxSP5lAIwu7w== +babel-plugin-jest-hoist@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz#4f837091eb407e01447c8843cbec546d0002d756" + integrity sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw== dependencies: "@types/babel__traverse" "^7.0.6" @@ -1892,13 +2041,13 @@ babel-plugin-transform-react-remove-prop-types@0.4.24: resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz#f2edaf9b4c6a5fbe5c1d678bfb531078c1555f3a" integrity sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA== -babel-preset-jest@^24.6.0: - version "24.6.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-24.6.0.tgz#66f06136eefce87797539c0d63f1769cc3915984" - integrity sha512-pdZqLEdmy1ZK5kyRUfvBb2IfTPb2BUvIJczlPspS8fWmBQslNNDBqVfh7BW5leOVJMDZKzjD8XEyABTk6gQ5yw== +babel-preset-jest@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz#192b521e2217fb1d1f67cf73f70c336650ad3cdc" + integrity sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg== dependencies: "@babel/plugin-syntax-object-rest-spread" "^7.0.0" - babel-plugin-jest-hoist "^24.6.0" + babel-plugin-jest-hoist "^24.9.0" babel-preset-react-app@^9.0.1: version "9.0.1" @@ -1922,7 +2071,7 @@ babel-preset-react-app@^9.0.1: babel-plugin-macros "2.6.1" babel-plugin-transform-react-remove-prop-types "0.4.24" -babel-runtime@^6.26.0: +babel-runtime@6.x, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= @@ -2179,9 +2328,9 @@ bytes@3.1.0: integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== cacache@^12.0.2: - version "12.0.2" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.2.tgz#8db03205e36089a3df6954c66ce92541441ac46c" - integrity sha512-ifKgxH2CKhJEg6tNdAwziu6Q33EvuG26tYcda6PT3WKisZcYDXsnEdnRv67Po3yCzFfaSoMjGZzJyD2c3DT1dg== + version "12.0.3" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.3.tgz#be99abba4e1bf5df461cd5a2c1071fc432573390" + integrity sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw== dependencies: bluebird "^3.5.5" chownr "^1.1.1" @@ -2324,9 +2473,9 @@ chardet@^0.7.0: integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== chokidar@^2.0.0, chokidar@^2.0.2, chokidar@^2.0.4: - version "2.1.6" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.6.tgz#b6cad653a929e244ce8a834244164d241fa954c5" - integrity sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g== + version "2.1.8" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" + integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== dependencies: anymatch "^2.0.0" async-each "^1.0.1" @@ -2377,6 +2526,11 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +classnames@2.x, classnames@^2.2.6: + version "2.2.6" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" + integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== + clean-css@4.2.x: version "4.2.1" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17" @@ -2391,13 +2545,6 @@ cli-cursor@^2.1.0: dependencies: restore-cursor "^2.0.0" -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" @@ -2412,6 +2559,15 @@ cliui@^4.0.0: strip-ansi "^4.0.0" wrap-ansi "^2.0.0" +cliui@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" + integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== + dependencies: + string-width "^3.1.0" + strip-ansi "^5.2.0" + wrap-ansi "^5.1.0" + clone-deep@^0.2.4: version "0.2.4" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-0.2.4.tgz#4e73dd09e9fb971cc38670c5dced9c1896481cc6" @@ -2432,6 +2588,11 @@ clone-deep@^4.0.1: kind-of "^6.0.2" shallow-clone "^3.0.0" +clone@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f" + integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18= + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -2524,11 +2685,23 @@ commondir@^1.0.1: resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= +component-classes@^1.2.5: + version "1.2.6" + resolved "https://registry.yarnpkg.com/component-classes/-/component-classes-1.2.6.tgz#c642394c3618a4d8b0b8919efccbbd930e5cd691" + integrity sha1-xkI5TDYYpNiwuJGe/Mu9kw5c1pE= + dependencies: + component-indexof "0.0.3" + component-emitter@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== +component-indexof@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/component-indexof/-/component-indexof-0.0.3.tgz#11d091312239eb8f32c8f25ae9cb002ffe8d3c24" + integrity sha1-EdCRMSI5648yyPJa6csAL/6NPCQ= + compose-function@3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/compose-function/-/compose-function-3.0.3.tgz#9ed675f13cc54501d30950a486ff6a7ba3ab185f" @@ -2632,7 +2805,7 @@ cookie-signature@1.0.6: resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= -cookie@0.4.0: +cookie@0.4.0, cookie@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== @@ -2667,7 +2840,7 @@ core-js@3.1.4: resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.1.4.tgz#3a2837fc48e582e1ae25907afcd6cf03b0cc7a07" integrity sha512-YNZN8lt82XIMLnLirj9MhKDFZHalwzzrL9YLt6eb0T5D0EDl4IQ90IGkua8mHbnxNrkj1d8hbdizMc0Qmg1WnQ== -core-js@^2.4.0: +core-js@^2.4.0, core-js@^2.6.5: version "2.6.9" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2" integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A== @@ -2718,6 +2891,14 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" +create-react-context@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/create-react-context/-/create-react-context-0.3.0.tgz#546dede9dc422def0d3fc2fe03afe0bc0f4f7d8c" + integrity sha512-dNldIoSuNSvlTJ7slIKC/ZFGKexBMBrrcc+TTe1NdmROnaASuLPvqpwj9v4XS4uXZ8+YPu0sNmShX2rXI5LNsw== + dependencies: + gud "^1.0.0" + warning "^4.0.3" + cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -2746,6 +2927,14 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" +css-animation@^1.3.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/css-animation/-/css-animation-1.6.1.tgz#162064a3b0d51f958b7ff37b3d6d4de18e17039e" + integrity sha512-/48+/BaEaHRY6kNQ2OIPzKf9A6g8WjZYjhiNDNuIVbsm5tXCGIAsHDjB4Xu1C4vXJtUWZo26O68OQkDpNBaPog== + dependencies: + babel-runtime "6.x" + component-classes "^1.2.5" + css-blank-pseudo@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5" @@ -3012,6 +3201,13 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.8, debug@^2.6. dependencies: ms "2.0.0" +debug@=3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + debug@^3.2.5, debug@^3.2.6: version "3.2.6" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" @@ -3158,10 +3354,10 @@ detect-port-alt@1.1.6: address "^1.0.1" debug "^2.6.0" -diff-sequences@^24.3.0: - version "24.3.0" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.3.0.tgz#0f20e8a1df1abddaf4d9c226680952e64118b975" - integrity sha512-xLqpez+Zj9GKSnPWS0WZw1igGocZ+uua8+y+5dDNTT934N3QuY1sp2LkHzwiaYQGz60hMq0pjAshdeXm5VUOEw== +diff-sequences@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5" + integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew== diffie-hellman@^5.0.0: version "5.0.3" @@ -3229,6 +3425,13 @@ dom-converter@^0.2: dependencies: utila "~0.4" +dom-helpers@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8" + integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA== + dependencies: + "@babel/runtime" "^7.1.2" + dom-serializer@0: version "0.2.1" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.2.1.tgz#13650c850daffea35d8b626a4cfc4d3a17643fdb" @@ -3328,9 +3531,9 @@ ee-first@1.1.1: integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= electron-to-chromium@^1.3.191: - version "1.3.225" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.225.tgz#c6786475b5eb5f491ade01a78b82ba2c5bfdf72b" - integrity sha512-7W/L3jw7HYE+tUPbcVOGBmnSrlUmyZ/Uyg24QS7Vx0a9KodtNrN0r0Q/LyGHrcYMtw2rv7E49F/vTXwlV/fuaA== + version "1.3.241" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.241.tgz#859dc49ab7f90773ed698767372d384190f60cb1" + integrity sha512-Gb9E6nWZlbgjDDNe5cAvMJixtn79krNJ70EDpq/M10lkGo7PGtBUe7Y0CYVHsBScRwi6ybCS+YetXAN9ysAHDg== elliptic@^6.0.0: version "6.5.0" @@ -3350,11 +3553,6 @@ emoji-regex@^7.0.1, emoji-regex@^7.0.2: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" @@ -3391,7 +3589,7 @@ entities@^2.0.0: resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw== -errno@^0.1.3, errno@~0.1.7: +errno@^0.1.1, errno@^0.1.3, errno@~0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== @@ -3591,22 +3789,22 @@ eslint-scope@^5.0.0: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-utils@^1.3.1: - version "1.4.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.0.tgz#e2c3c8dba768425f897cf0f9e51fe2e241485d4c" - integrity sha512-7ehnzPaP5IIEh1r1tkjuIrxqhNkzUJa9z3R92tLJdZIVdWaczEhr3EbhGtsMrVxi1KeR8qA7Off6SWc5WNQqyQ== +eslint-utils@^1.3.1, eslint-utils@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab" + integrity sha512-eAZS2sEUMlIeCjBeubdj45dmBHQwPHWyBcT1VSYB7o9x9WRRqKxyUoiXlRjyAwzN7YEzHJlYg0NmzDRWx6GP4Q== dependencies: eslint-visitor-keys "^1.0.0" -eslint-visitor-keys@^1.0.0: +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== eslint@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.1.0.tgz#06438a4a278b1d84fb107d24eaaa35471986e646" - integrity sha512-QhrbdRD7ofuV09IuE2ySWBz0FyXCq0rriLTZXZqaWSI79CVtHVRdkFuFTViiqzZhkCgfOh9USpriuGN2gIpZDQ== + version "6.2.2" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.2.2.tgz#03298280e7750d81fcd31431f3d333e43d93f24f" + integrity sha512-mf0elOkxHbdyGX1IJEUsNBzCDdyoUgljF3rRlgfyYh0pwGnreLc0jjD6ZuleOibjmnUWZLY2eXwSooeOgGJ2jw== dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.10.0" @@ -3615,9 +3813,9 @@ eslint@^6.1.0: debug "^4.0.1" doctrine "^3.0.0" eslint-scope "^5.0.0" - eslint-utils "^1.3.1" - eslint-visitor-keys "^1.0.0" - espree "^6.0.0" + eslint-utils "^1.4.2" + eslint-visitor-keys "^1.1.0" + espree "^6.1.1" esquery "^1.0.1" esutils "^2.0.2" file-entry-cache "^5.0.1" @@ -3646,14 +3844,14 @@ eslint@^6.1.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-6.0.0.tgz#716fc1f5a245ef5b9a7fdb1d7b0d3f02322e75f6" - integrity sha512-lJvCS6YbCn3ImT3yKkPe0+tJ+mH6ljhGNjHQH9mRtiO6gjhVAOhVXW1yjnwqGwTkK3bGbye+hb00nFNmu0l/1Q== +espree@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-6.1.1.tgz#7f80e5f7257fc47db450022d723e356daeb1e5de" + integrity sha512-EYbr8XZUhWbYCqQRW0duU5LxzL5bETN6AjKBGy1302qqzPaCH10QbRg3Wvco79Z8x9WbiE8HYB4e75xl6qUYvQ== dependencies: - acorn "^6.0.7" - acorn-jsx "^5.0.0" - eslint-visitor-keys "^1.0.0" + acorn "^7.0.0" + acorn-jsx "^5.0.2" + eslint-visitor-keys "^1.1.0" esprima@^3.1.3: version "3.1.3" @@ -3680,9 +3878,9 @@ esrecurse@^4.1.0: estraverse "^4.1.0" estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" - integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== esutils@^2.0.0, esutils@^2.0.2: version "2.0.3" @@ -3737,6 +3935,11 @@ execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" +exenv@^1.2.0, exenv@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d" + integrity sha1-KueOhdmJQVhnCwPUe+wfA72Ru50= + exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -3755,17 +3958,17 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" -expect@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-24.8.0.tgz#471f8ec256b7b6129ca2524b2a62f030df38718d" - integrity sha512-/zYvP8iMDrzaaxHVa724eJBCKqSHmO0FA7EDkBiRHxg6OipmMn1fN+C8T9L9K8yr7UONkOifu6+LLH+z76CnaA== +expect@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-24.9.0.tgz#b75165b4817074fa4a157794f46fe9f1ba15b6ca" + integrity sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q== dependencies: - "@jest/types" "^24.8.0" + "@jest/types" "^24.9.0" ansi-styles "^3.2.0" - jest-get-type "^24.8.0" - jest-matcher-utils "^24.8.0" - jest-message-util "^24.8.0" - jest-regex-util "^24.3.0" + jest-get-type "^24.9.0" + jest-matcher-utils "^24.9.0" + jest-message-util "^24.9.0" + jest-regex-util "^24.9.0" express@^4.16.2: version "4.17.1" @@ -3916,13 +4119,6 @@ figures@^2.0.0: dependencies: escape-string-regexp "^1.0.5" -figures@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.0.0.tgz#756275c964646163cc6f9197c7a0295dbfd04de9" - integrity sha512-HKri+WoWoUgr83pehn/SIgLOMZ9nAWC6dcGj26RY2R4F50u4+RTUz0RCrUlOV3nKRAICW1UGzyb+kcX2qK1S/g== - dependencies: - escape-string-regexp "^1.0.5" - file-entry-cache@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" @@ -4033,6 +4229,13 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" readable-stream "^2.3.6" +follow-redirects@1.5.10: + version "1.5.10" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" + integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== + dependencies: + debug "=3.1.0" + follow-redirects@^1.0.0: version "1.7.0" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76" @@ -4192,6 +4395,11 @@ get-caller-file@^1.0.1: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== +get-caller-file@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + get-own-enumerable-property-symbols@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.0.tgz#b877b49a5c16aefac3655f2ed2ea5b684df8d203" @@ -4294,15 +4502,20 @@ globby@^6.1.0: pinkie-promise "^2.0.0" graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6: - version "4.2.1" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.1.tgz#1c1f0c364882c868f5bff6512146328336a11b1d" - integrity sha512-b9usnbDGnD928gJB3LrCmxoibr3VE4U2SMo5PBuBnokWyDADTqDPXg4YpwKF1trpH+UbGp7QLicO3+aWEy0+mw== + version "4.2.2" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02" + integrity sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q== growly@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= +gud@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0" + integrity sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw== + gzip-size@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.1.1.tgz#cb9bee692f87c0612b232840a873904e4c135274" @@ -4431,6 +4644,18 @@ hex-color-regex@^1.1.0: resolved "https://registry.yarnpkg.com/hex-color-regex/-/hex-color-regex-1.1.0.tgz#4c06fccb4602fe2602b3c93df82d7e7dbf1a8a8e" integrity sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ== +history@^4.9.0: + version "4.9.0" + resolved "https://registry.yarnpkg.com/history/-/history-4.9.0.tgz#84587c2068039ead8af769e9d6a6860a14fa1bca" + integrity sha512-H2DkjCjXf0Op9OAr6nJ56fcRkTSNrUiv41vNJ6IswJjif6wlpZK0BTfFbi7qK9dXLSYZxkq5lBsj3vUjlYBYZA== + dependencies: + "@babel/runtime" "^7.1.2" + loose-envify "^1.2.0" + resolve-pathname "^2.2.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + value-equal "^0.4.0" + hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -4440,6 +4665,13 @@ hmac-drbg@^1.0.0: minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" +hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.0.tgz#b09178f0122184fb95acf525daaecb4d8f45958b" + integrity sha512-0XsbTXxgiaCDYDIWFcwkmerZPSwywfUqYmwT4jzewKTQSWoE6FCMoUVOeBJWK3E/CrWbxRG3m5GzY4lnIwGRBA== + dependencies: + react-is "^16.7.0" + hosted-git-info@^2.1.4: version "2.8.4" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.4.tgz#44119abaf4bc64692a16ace34700fed9c03e2546" @@ -4507,7 +4739,7 @@ html-webpack-plugin@4.0.0-beta.5: tapable "^1.1.0" util.promisify "1.0.0" -htmlparser2@^3.3.0: +htmlparser2@^3.3.0, htmlparser2@^3.9.0: version "3.10.1" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== @@ -4647,6 +4879,11 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +image-size@~0.5.0: + version "0.5.5" + resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" + integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w= + immer@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d" @@ -4753,21 +4990,21 @@ inquirer@6.5.0: through "^2.3.6" inquirer@^6.4.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.1.tgz#8bfb7a5ac02dac6ff641ac4c5ff17da112fcdb42" - integrity sha512-uxNHBeQhRXIoHWTSNYUFhQVrHYFThIt6IVo2fFmSe8aBwdR3/w6b58hJpiL/fMukFkvGzjg+hSxFtwvVmKZmXw== + version "6.5.2" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" + integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== dependencies: - ansi-escapes "^4.2.1" + ansi-escapes "^3.2.0" chalk "^2.4.2" - cli-cursor "^3.1.0" + cli-cursor "^2.1.0" cli-width "^2.0.0" external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.15" - mute-stream "0.0.8" + figures "^2.0.0" + lodash "^4.17.12" + mute-stream "0.0.7" run-async "^2.2.0" rxjs "^6.4.0" - string-width "^4.1.0" + string-width "^2.1.0" strip-ansi "^5.1.0" through "^2.3.6" @@ -4852,6 +5089,11 @@ is-buffer@^1.0.2, is-buffer@^1.1.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== +is-buffer@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725" + integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw== + is-callable@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" @@ -4947,11 +5189,6 @@ is-fullwidth-code-point@^2.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - is-generator-fn@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" @@ -5070,6 +5307,11 @@ is-wsl@^1.1.0: resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -5135,91 +5377,91 @@ istanbul-lib-source-maps@^3.0.1: rimraf "^2.6.3" source-map "^0.6.1" -istanbul-reports@^2.1.1: +istanbul-reports@^2.2.6: version "2.2.6" resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.2.6.tgz#7b4f2660d82b29303a8fe6091f8ca4bf058da1af" integrity sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA== dependencies: handlebars "^4.1.2" -jest-changed-files@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.8.0.tgz#7e7eb21cf687587a85e50f3d249d1327e15b157b" - integrity sha512-qgANC1Yrivsq+UrLXsvJefBKVoCsKB0Hv+mBb6NMjjZ90wwxCDmU3hsCXBya30cH+LnPYjwgcU65i6yJ5Nfuug== +jest-changed-files@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.9.0.tgz#08d8c15eb79a7fa3fc98269bc14b451ee82f8039" + integrity sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg== dependencies: - "@jest/types" "^24.8.0" + "@jest/types" "^24.9.0" execa "^1.0.0" throat "^4.0.0" jest-cli@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-24.8.0.tgz#b075ac914492ed114fa338ade7362a301693e989" - integrity sha512-+p6J00jSMPQ116ZLlHJJvdf8wbjNbZdeSX9ptfHX06/MSNaXmKihQzx5vQcw0q2G6JsdVkUIdWbOWtSnaYs3yA== + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-24.9.0.tgz#ad2de62d07472d419c6abc301fc432b98b10d2af" + integrity sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg== dependencies: - "@jest/core" "^24.8.0" - "@jest/test-result" "^24.8.0" - "@jest/types" "^24.8.0" + "@jest/core" "^24.9.0" + "@jest/test-result" "^24.9.0" + "@jest/types" "^24.9.0" chalk "^2.0.1" exit "^0.1.2" import-local "^2.0.0" is-ci "^2.0.0" - jest-config "^24.8.0" - jest-util "^24.8.0" - jest-validate "^24.8.0" + jest-config "^24.9.0" + jest-util "^24.9.0" + jest-validate "^24.9.0" prompts "^2.0.1" realpath-native "^1.1.0" - yargs "^12.0.2" + yargs "^13.3.0" -jest-config@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-24.8.0.tgz#77db3d265a6f726294687cbbccc36f8a76ee0f4f" - integrity sha512-Czl3Nn2uEzVGsOeaewGWoDPD8GStxCpAe0zOYs2x2l0fZAgPbCr3uwUkgNKV3LwE13VXythM946cd5rdGkkBZw== +jest-config@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-24.9.0.tgz#fb1bbc60c73a46af03590719efa4825e6e4dd1b5" + integrity sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ== dependencies: "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^24.8.0" - "@jest/types" "^24.8.0" - babel-jest "^24.8.0" + "@jest/test-sequencer" "^24.9.0" + "@jest/types" "^24.9.0" + babel-jest "^24.9.0" chalk "^2.0.1" glob "^7.1.1" - jest-environment-jsdom "^24.8.0" - jest-environment-node "^24.8.0" - jest-get-type "^24.8.0" - jest-jasmine2 "^24.8.0" + jest-environment-jsdom "^24.9.0" + jest-environment-node "^24.9.0" + jest-get-type "^24.9.0" + jest-jasmine2 "^24.9.0" jest-regex-util "^24.3.0" - jest-resolve "^24.8.0" - jest-util "^24.8.0" - jest-validate "^24.8.0" + jest-resolve "^24.9.0" + jest-util "^24.9.0" + jest-validate "^24.9.0" micromatch "^3.1.10" - pretty-format "^24.8.0" + pretty-format "^24.9.0" realpath-native "^1.1.0" -jest-diff@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.8.0.tgz#146435e7d1e3ffdf293d53ff97e193f1d1546172" - integrity sha512-wxetCEl49zUpJ/bvUmIFjd/o52J+yWcoc5ZyPq4/W1LUKGEhRYDIbP1KcF6t+PvqNrGAFk4/JhtxDq/Nnzs66g== +jest-diff@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da" + integrity sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ== dependencies: chalk "^2.0.1" - diff-sequences "^24.3.0" - jest-get-type "^24.8.0" - pretty-format "^24.8.0" + diff-sequences "^24.9.0" + jest-get-type "^24.9.0" + pretty-format "^24.9.0" jest-docblock@^24.3.0: - version "24.3.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-24.3.0.tgz#b9c32dac70f72e4464520d2ba4aec02ab14db5dd" - integrity sha512-nlANmF9Yq1dufhFlKG9rasfQlrY7wINJbo3q01tu56Jv5eBU5jirylhF2O5ZBnLxzOVBGRDz/9NAwNyBtG4Nyg== + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-24.9.0.tgz#7970201802ba560e1c4092cc25cbedf5af5a8ce2" + integrity sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA== dependencies: detect-newline "^2.1.0" -jest-each@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-24.8.0.tgz#a05fd2bf94ddc0b1da66c6d13ec2457f35e52775" - integrity sha512-NrwK9gaL5+XgrgoCsd9svsoWdVkK4gnvyhcpzd6m487tXHqIdYeykgq3MKI1u4I+5Zf0tofr70at9dWJDeb+BA== +jest-each@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-24.9.0.tgz#eb2da602e2a610898dbc5f1f6df3ba86b55f8b05" + integrity sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog== dependencies: - "@jest/types" "^24.8.0" + "@jest/types" "^24.9.0" chalk "^2.0.1" - jest-get-type "^24.8.0" - jest-util "^24.8.0" - pretty-format "^24.8.0" + jest-get-type "^24.9.0" + jest-util "^24.9.0" + pretty-format "^24.9.0" jest-environment-jsdom-fourteen@0.1.0: version "0.1.0" @@ -5230,133 +5472,134 @@ jest-environment-jsdom-fourteen@0.1.0: jest-util "^24.5.0" jsdom "^14.0.0" -jest-environment-jsdom@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-24.8.0.tgz#300f6949a146cabe1c9357ad9e9ecf9f43f38857" - integrity sha512-qbvgLmR7PpwjoFjM/sbuqHJt/NCkviuq9vus9NBn/76hhSidO+Z6Bn9tU8friecegbJL8gzZQEMZBQlFWDCwAQ== +jest-environment-jsdom@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz#4b0806c7fc94f95edb369a69cc2778eec2b7375b" + integrity sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA== dependencies: - "@jest/environment" "^24.8.0" - "@jest/fake-timers" "^24.8.0" - "@jest/types" "^24.8.0" - jest-mock "^24.8.0" - jest-util "^24.8.0" + "@jest/environment" "^24.9.0" + "@jest/fake-timers" "^24.9.0" + "@jest/types" "^24.9.0" + jest-mock "^24.9.0" + jest-util "^24.9.0" jsdom "^11.5.1" -jest-environment-node@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-24.8.0.tgz#d3f726ba8bc53087a60e7a84ca08883a4c892231" - integrity sha512-vIGUEScd1cdDgR6sqn2M08sJTRLQp6Dk/eIkCeO4PFHxZMOgy+uYLPMC4ix3PEfM5Au/x3uQ/5Tl0DpXXZsJ/Q== +jest-environment-node@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-24.9.0.tgz#333d2d2796f9687f2aeebf0742b519f33c1cbfd3" + integrity sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA== dependencies: - "@jest/environment" "^24.8.0" - "@jest/fake-timers" "^24.8.0" - "@jest/types" "^24.8.0" - jest-mock "^24.8.0" - jest-util "^24.8.0" + "@jest/environment" "^24.9.0" + "@jest/fake-timers" "^24.9.0" + "@jest/types" "^24.9.0" + jest-mock "^24.9.0" + jest-util "^24.9.0" -jest-get-type@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.8.0.tgz#a7440de30b651f5a70ea3ed7ff073a32dfe646fc" - integrity sha512-RR4fo8jEmMD9zSz2nLbs2j0zvPpk/KCEz3a62jJWbd2ayNo0cb+KFRxPHVhE4ZmgGJEQp0fosmNz84IfqM8cMQ== +jest-get-type@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e" + integrity sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q== -jest-haste-map@^24.8.0: - version "24.8.1" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.8.1.tgz#f39cc1d2b1d907e014165b4bd5a957afcb992982" - integrity sha512-SwaxMGVdAZk3ernAx2Uv2sorA7jm3Kx+lR0grp6rMmnY06Kn/urtKx1LPN2mGTea4fCT38impYT28FfcLUhX0g== +jest-haste-map@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.9.0.tgz#b38a5d64274934e21fa417ae9a9fbeb77ceaac7d" + integrity sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ== dependencies: - "@jest/types" "^24.8.0" + "@jest/types" "^24.9.0" anymatch "^2.0.0" fb-watchman "^2.0.0" graceful-fs "^4.1.15" invariant "^2.2.4" - jest-serializer "^24.4.0" - jest-util "^24.8.0" - jest-worker "^24.6.0" + jest-serializer "^24.9.0" + jest-util "^24.9.0" + jest-worker "^24.9.0" micromatch "^3.1.10" sane "^4.0.3" walker "^1.0.7" optionalDependencies: fsevents "^1.2.7" -jest-jasmine2@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-24.8.0.tgz#a9c7e14c83dd77d8b15e820549ce8987cc8cd898" - integrity sha512-cEky88npEE5LKd5jPpTdDCLvKkdyklnaRycBXL6GNmpxe41F0WN44+i7lpQKa/hcbXaQ+rc9RMaM4dsebrYong== +jest-jasmine2@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz#1f7b1bd3242c1774e62acabb3646d96afc3be6a0" + integrity sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw== dependencies: "@babel/traverse" "^7.1.0" - "@jest/environment" "^24.8.0" - "@jest/test-result" "^24.8.0" - "@jest/types" "^24.8.0" + "@jest/environment" "^24.9.0" + "@jest/test-result" "^24.9.0" + "@jest/types" "^24.9.0" chalk "^2.0.1" co "^4.6.0" - expect "^24.8.0" + expect "^24.9.0" is-generator-fn "^2.0.0" - jest-each "^24.8.0" - jest-matcher-utils "^24.8.0" - jest-message-util "^24.8.0" - jest-runtime "^24.8.0" - jest-snapshot "^24.8.0" - jest-util "^24.8.0" - pretty-format "^24.8.0" + jest-each "^24.9.0" + jest-matcher-utils "^24.9.0" + jest-message-util "^24.9.0" + jest-runtime "^24.9.0" + jest-snapshot "^24.9.0" + jest-util "^24.9.0" + pretty-format "^24.9.0" throat "^4.0.0" -jest-leak-detector@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-24.8.0.tgz#c0086384e1f650c2d8348095df769f29b48e6980" - integrity sha512-cG0yRSK8A831LN8lIHxI3AblB40uhv0z+SsQdW3GoMMVcK+sJwrIIyax5tu3eHHNJ8Fu6IMDpnLda2jhn2pD/g== +jest-leak-detector@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz#b665dea7c77100c5c4f7dfcb153b65cf07dcf96a" + integrity sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA== dependencies: - pretty-format "^24.8.0" + jest-get-type "^24.9.0" + pretty-format "^24.9.0" -jest-matcher-utils@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-24.8.0.tgz#2bce42204c9af12bde46f83dc839efe8be832495" - integrity sha512-lex1yASY51FvUuHgm0GOVj7DCYEouWSlIYmCW7APSqB9v8mXmKSn5+sWVF0MhuASG0bnYY106/49JU1FZNl5hw== +jest-matcher-utils@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz#f5b3661d5e628dffe6dd65251dfdae0e87c3a073" + integrity sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA== dependencies: chalk "^2.0.1" - jest-diff "^24.8.0" - jest-get-type "^24.8.0" - pretty-format "^24.8.0" + jest-diff "^24.9.0" + jest-get-type "^24.9.0" + pretty-format "^24.9.0" -jest-message-util@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.8.0.tgz#0d6891e72a4beacc0292b638685df42e28d6218b" - integrity sha512-p2k71rf/b6ns8btdB0uVdljWo9h0ovpnEe05ZKWceQGfXYr4KkzgKo3PBi8wdnd9OtNh46VpNIJynUn/3MKm1g== +jest-message-util@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.9.0.tgz#527f54a1e380f5e202a8d1149b0ec872f43119e3" + integrity sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw== dependencies: "@babel/code-frame" "^7.0.0" - "@jest/test-result" "^24.8.0" - "@jest/types" "^24.8.0" + "@jest/test-result" "^24.9.0" + "@jest/types" "^24.9.0" "@types/stack-utils" "^1.0.1" chalk "^2.0.1" micromatch "^3.1.10" slash "^2.0.0" stack-utils "^1.0.1" -jest-mock@^24.5.0, jest-mock@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.8.0.tgz#2f9d14d37699e863f1febf4e4d5a33b7fdbbde56" - integrity sha512-6kWugwjGjJw+ZkK4mDa0Df3sDlUTsV47MSrT0nGQ0RBWJbpODDQ8MHDVtGtUYBne3IwZUhtB7elxHspU79WH3A== +jest-mock@^24.5.0, jest-mock@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.9.0.tgz#c22835541ee379b908673ad51087a2185c13f1c6" + integrity sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w== dependencies: - "@jest/types" "^24.8.0" + "@jest/types" "^24.9.0" jest-pnp-resolver@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz#ecdae604c077a7fbc70defb6d517c3c1c898923a" integrity sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ== -jest-regex-util@^24.3.0: - version "24.3.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.3.0.tgz#d5a65f60be1ae3e310d5214a0307581995227b36" - integrity sha512-tXQR1NEOyGlfylyEjg1ImtScwMq8Oh3iJbGTjN7p0J23EuVX1MA8rwU69K4sLbCmwzgCUbVkm0FkSF9TdzOhtg== +jest-regex-util@^24.3.0, jest-regex-util@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.9.0.tgz#c13fb3380bde22bf6575432c493ea8fe37965636" + integrity sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA== -jest-resolve-dependencies@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-24.8.0.tgz#19eec3241f2045d3f990dba331d0d7526acff8e0" - integrity sha512-hyK1qfIf/krV+fSNyhyJeq3elVMhK9Eijlwy+j5jqmZ9QsxwKBiP6qukQxaHtK8k6zql/KYWwCTQ+fDGTIJauw== +jest-resolve-dependencies@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz#ad055198959c4cfba8a4f066c673a3f0786507ab" + integrity sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g== dependencies: - "@jest/types" "^24.8.0" + "@jest/types" "^24.9.0" jest-regex-util "^24.3.0" - jest-snapshot "^24.8.0" + jest-snapshot "^24.9.0" -jest-resolve@24.8.0, jest-resolve@^24.8.0: +jest-resolve@24.8.0: version "24.8.0" resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-24.8.0.tgz#84b8e5408c1f6a11539793e2b5feb1b6e722439f" integrity sha512-+hjSzi1PoRvnuOICoYd5V/KpIQmkAsfjFO71458hQ2Whi/yf1GDeBOFj8Gxw4LrApHsVJvn5fmjcPdmoUHaVKw== @@ -5367,93 +5610,105 @@ jest-resolve@24.8.0, jest-resolve@^24.8.0: jest-pnp-resolver "^1.2.1" realpath-native "^1.1.0" -jest-runner@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-24.8.0.tgz#4f9ae07b767db27b740d7deffad0cf67ccb4c5bb" - integrity sha512-utFqC5BaA3JmznbissSs95X1ZF+d+4WuOWwpM9+Ak356YtMhHE/GXUondZdcyAAOTBEsRGAgH/0TwLzfI9h7ow== +jest-resolve@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-24.9.0.tgz#dff04c7687af34c4dd7e524892d9cf77e5d17321" + integrity sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ== + dependencies: + "@jest/types" "^24.9.0" + browser-resolve "^1.11.3" + chalk "^2.0.1" + jest-pnp-resolver "^1.2.1" + realpath-native "^1.1.0" + +jest-runner@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-24.9.0.tgz#574fafdbd54455c2b34b4bdf4365a23857fcdf42" + integrity sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg== dependencies: "@jest/console" "^24.7.1" - "@jest/environment" "^24.8.0" - "@jest/test-result" "^24.8.0" - "@jest/types" "^24.8.0" + "@jest/environment" "^24.9.0" + "@jest/test-result" "^24.9.0" + "@jest/types" "^24.9.0" chalk "^2.4.2" exit "^0.1.2" graceful-fs "^4.1.15" - jest-config "^24.8.0" + jest-config "^24.9.0" jest-docblock "^24.3.0" - jest-haste-map "^24.8.0" - jest-jasmine2 "^24.8.0" - jest-leak-detector "^24.8.0" - jest-message-util "^24.8.0" - jest-resolve "^24.8.0" - jest-runtime "^24.8.0" - jest-util "^24.8.0" + jest-haste-map "^24.9.0" + jest-jasmine2 "^24.9.0" + jest-leak-detector "^24.9.0" + jest-message-util "^24.9.0" + jest-resolve "^24.9.0" + jest-runtime "^24.9.0" + jest-util "^24.9.0" jest-worker "^24.6.0" source-map-support "^0.5.6" throat "^4.0.0" -jest-runtime@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-24.8.0.tgz#05f94d5b05c21f6dc54e427cd2e4980923350620" - integrity sha512-Mq0aIXhvO/3bX44ccT+czU1/57IgOMyy80oM0XR/nyD5zgBcesF84BPabZi39pJVA6UXw+fY2Q1N+4BiVUBWOA== +jest-runtime@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-24.9.0.tgz#9f14583af6a4f7314a6a9d9f0226e1a781c8e4ac" + integrity sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw== dependencies: "@jest/console" "^24.7.1" - "@jest/environment" "^24.8.0" + "@jest/environment" "^24.9.0" "@jest/source-map" "^24.3.0" - "@jest/transform" "^24.8.0" - "@jest/types" "^24.8.0" - "@types/yargs" "^12.0.2" + "@jest/transform" "^24.9.0" + "@jest/types" "^24.9.0" + "@types/yargs" "^13.0.0" chalk "^2.0.1" exit "^0.1.2" glob "^7.1.3" graceful-fs "^4.1.15" - jest-config "^24.8.0" - jest-haste-map "^24.8.0" - jest-message-util "^24.8.0" - jest-mock "^24.8.0" + jest-config "^24.9.0" + jest-haste-map "^24.9.0" + jest-message-util "^24.9.0" + jest-mock "^24.9.0" jest-regex-util "^24.3.0" - jest-resolve "^24.8.0" - jest-snapshot "^24.8.0" - jest-util "^24.8.0" - jest-validate "^24.8.0" + jest-resolve "^24.9.0" + jest-snapshot "^24.9.0" + jest-util "^24.9.0" + jest-validate "^24.9.0" realpath-native "^1.1.0" slash "^2.0.0" strip-bom "^3.0.0" - yargs "^12.0.2" + yargs "^13.3.0" -jest-serializer@^24.4.0: - version "24.4.0" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.4.0.tgz#f70c5918c8ea9235ccb1276d232e459080588db3" - integrity sha512-k//0DtglVstc1fv+GY/VHDIjrtNjdYvYjMlbLUed4kxrE92sIUewOi5Hj3vrpB8CXfkJntRPDRjCrCvUhBdL8Q== +jest-serializer@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.9.0.tgz#e6d7d7ef96d31e8b9079a714754c5d5c58288e73" + integrity sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ== -jest-snapshot@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-24.8.0.tgz#3bec6a59da2ff7bc7d097a853fb67f9d415cb7c6" - integrity sha512-5ehtWoc8oU9/cAPe6fez6QofVJLBKyqkY2+TlKTOf0VllBB/mqUNdARdcjlZrs9F1Cv+/HKoCS/BknT0+tmfPg== +jest-snapshot@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-24.9.0.tgz#ec8e9ca4f2ec0c5c87ae8f925cf97497b0e951ba" + integrity sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew== dependencies: "@babel/types" "^7.0.0" - "@jest/types" "^24.8.0" + "@jest/types" "^24.9.0" chalk "^2.0.1" - expect "^24.8.0" - jest-diff "^24.8.0" - jest-matcher-utils "^24.8.0" - jest-message-util "^24.8.0" - jest-resolve "^24.8.0" + expect "^24.9.0" + jest-diff "^24.9.0" + jest-get-type "^24.9.0" + jest-matcher-utils "^24.9.0" + jest-message-util "^24.9.0" + jest-resolve "^24.9.0" mkdirp "^0.5.1" natural-compare "^1.4.0" - pretty-format "^24.8.0" - semver "^5.5.0" + pretty-format "^24.9.0" + semver "^6.2.0" -jest-util@^24.5.0, jest-util@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.8.0.tgz#41f0e945da11df44cc76d64ffb915d0716f46cd1" - integrity sha512-DYZeE+XyAnbNt0BG1OQqKy/4GVLPtzwGx5tsnDrFcax36rVE3lTA5fbvgmbVPUZf9w77AJ8otqR4VBbfFJkUZA== +jest-util@^24.5.0, jest-util@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.9.0.tgz#7396814e48536d2e85a37de3e4c431d7cb140162" + integrity sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg== dependencies: - "@jest/console" "^24.7.1" - "@jest/fake-timers" "^24.8.0" - "@jest/source-map" "^24.3.0" - "@jest/test-result" "^24.8.0" - "@jest/types" "^24.8.0" + "@jest/console" "^24.9.0" + "@jest/fake-timers" "^24.9.0" + "@jest/source-map" "^24.9.0" + "@jest/test-result" "^24.9.0" + "@jest/types" "^24.9.0" callsites "^3.0.0" chalk "^2.0.1" graceful-fs "^4.1.15" @@ -5462,17 +5717,17 @@ jest-util@^24.5.0, jest-util@^24.8.0: slash "^2.0.0" source-map "^0.6.0" -jest-validate@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-24.8.0.tgz#624c41533e6dfe356ffadc6e2423a35c2d3b4849" - integrity sha512-+/N7VOEMW1Vzsrk3UWBDYTExTPwf68tavEPKDnJzrC6UlHtUDU/fuEdXqFoHzv9XnQ+zW6X3qMZhJ3YexfeLDA== +jest-validate@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-24.9.0.tgz#0775c55360d173cd854e40180756d4ff52def8ab" + integrity sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ== dependencies: - "@jest/types" "^24.8.0" - camelcase "^5.0.0" + "@jest/types" "^24.9.0" + camelcase "^5.3.1" chalk "^2.0.1" - jest-get-type "^24.8.0" - leven "^2.1.0" - pretty-format "^24.8.0" + jest-get-type "^24.9.0" + leven "^3.1.0" + pretty-format "^24.9.0" jest-watch-typeahead@0.3.1: version "0.3.1" @@ -5486,25 +5741,25 @@ jest-watch-typeahead@0.3.1: string-length "^2.0.0" strip-ansi "^5.0.0" -jest-watcher@^24.3.0, jest-watcher@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-24.8.0.tgz#58d49915ceddd2de85e238f6213cef1c93715de4" - integrity sha512-SBjwHt5NedQoVu54M5GEx7cl7IGEFFznvd/HNT8ier7cCAx/Qgu9ZMlaTQkvK22G1YOpcWBLQPFSImmxdn3DAw== +jest-watcher@^24.3.0, jest-watcher@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-24.9.0.tgz#4b56e5d1ceff005f5b88e528dc9afc8dd4ed2b3b" + integrity sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw== dependencies: - "@jest/test-result" "^24.8.0" - "@jest/types" "^24.8.0" - "@types/yargs" "^12.0.9" + "@jest/test-result" "^24.9.0" + "@jest/types" "^24.9.0" + "@types/yargs" "^13.0.0" ansi-escapes "^3.0.0" chalk "^2.0.1" - jest-util "^24.8.0" + jest-util "^24.9.0" string-length "^2.0.0" -jest-worker@^24.6.0: - version "24.6.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.6.0.tgz#7f81ceae34b7cde0c9827a6980c35b7cdc0161b3" - integrity sha512-jDwgW5W9qGNvpI1tNnvajh0a5IE/PuGLFmHk6aR/BZFz8tSgGw17GsDPXAJ6p91IvYDjOw8GpFbvvZGAK+DPQQ== +jest-worker@^24.6.0, jest-worker@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5" + integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw== dependencies: - merge-stream "^1.0.1" + merge-stream "^2.0.0" supports-color "^6.1.0" jest@24.8.0: @@ -5769,10 +6024,26 @@ left-pad@^1.3.0: resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" integrity sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA== -leven@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" - integrity sha1-wuep93IJTe6dNCAq6KzORoeHVYA= +less@^3.10.3: + version "3.10.3" + resolved "https://registry.yarnpkg.com/less/-/less-3.10.3.tgz#417a0975d5eeecc52cff4bcfa3c09d35781e6792" + integrity sha512-vz32vqfgmoxF1h3K4J+yKCtajH0PWmjkIFgbs5d78E/c/e+UQTnI+lWK+1eQRE95PXM2mC3rJlLSSP9VQHnaow== + dependencies: + clone "^2.1.2" + optionalDependencies: + errno "^0.1.1" + graceful-fs "^4.1.2" + image-size "~0.5.0" + mime "^1.4.1" + mkdirp "^0.5.0" + promise "^7.1.1" + request "^2.83.0" + source-map "~0.6.0" + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== levn@^0.3.0, levn@~0.3.0: version "0.3.0" @@ -5840,11 +6111,35 @@ locate-path@^3.0.0: p-locate "^3.0.0" path-exists "^3.0.0" +lodash._getnative@^3.0.0: + version "3.9.1" + resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" + integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U= + lodash._reinterpolate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= +lodash.isarguments@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + integrity sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U= + +lodash.keys@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" + integrity sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo= + dependencies: + lodash._getnative "^3.0.0" + lodash.isarguments "^3.0.0" + lodash.isarray "^3.0.0" + lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" @@ -5880,7 +6175,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.5: +"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@^4.17.5: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== @@ -5890,7 +6185,12 @@ loglevel@^1.4.1: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.3.tgz#77f2eb64be55a404c9fd04ad16d57c1d6d6b1280" integrity sha512-LoEDv5pgpvWgPF4kNYuIp0qqSJVWak/dML0RY74xlzMZiT9w77teNAwKYKWBTYjlokMirg+o3jBwp+vlLrcfAA== -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0: +lokijs@^1.5.7: + version "1.5.7" + resolved "https://registry.yarnpkg.com/lokijs/-/lokijs-1.5.7.tgz#3bbeb5c2dbffebd78d035bac82c7c4e6055870f0" + integrity sha512-2SqUV6JH4f15Z5/7LVsyadSUwHhZppxhujgy/VhVqiRYMGt5oaocb7fV/3JGjHJ6rTuEIajnpTLGRz9cJW/c3g== + +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -6003,12 +6303,10 @@ merge-descriptors@1.0.1: resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= -merge-stream@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" - integrity sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE= - dependencies: - readable-stream "^2.0.1" +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== merge2@^1.2.3: version "1.2.4" @@ -6064,7 +6362,7 @@ mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24: dependencies: mime-db "1.40.0" -mime@1.6.0: +mime@1.6.0, mime@^1.4.1: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== @@ -6079,11 +6377,20 @@ mimic-fn@^1.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== -mimic-fn@^2.0.0, mimic-fn@^2.1.0: +mimic-fn@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mini-create-react-context@^0.3.0: + version "0.3.2" + resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.3.2.tgz#79fc598f283dd623da8e088b05db8cddab250189" + integrity sha512-2v+OeetEyliMt5VHMXsBhABoJ0/M4RCe7fatd/fBy6SMiKazUSEt3gxxypfnk2SHMkdBYvorHRoQxuGoiwbzAw== + dependencies: + "@babel/runtime" "^7.4.0" + gud "^1.0.0" + tiny-warning "^1.0.2" + mini-css-extract-plugin@0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.5.0.tgz#ac0059b02b9692515a637115b0cc9fed3a35c7b0" @@ -6126,9 +6433,9 @@ minimist@~0.0.1: integrity sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8= minipass@^2.2.1, minipass@^2.3.5: - version "2.3.5" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" - integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== + version "2.4.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.4.0.tgz#38f0af94f42fb6f34d3d7d82a90e2c99cd3ff485" + integrity sha512-6PmOuSP4NnZXzs2z6rbwzLJu/c5gdzYg1mRI/WIYdx45iiX7T+a4esOzavD6V/KmBzAaopFSTZPZcUx73bqKWA== dependencies: safe-buffer "^5.1.2" yallist "^3.0.0" @@ -6179,6 +6486,11 @@ mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: dependencies: minimist "0.0.8" +moment@^2.24.0: + version "2.24.0" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" + integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== + move-concurrently@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" @@ -6224,11 +6536,6 @@ mute-stream@0.0.7: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= -mute-stream@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== - nan@^2.12.1: version "2.14.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" @@ -6336,10 +6643,10 @@ node-modules-regexp@^1.0.0: resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= -node-notifier@^5.2.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.4.1.tgz#7c0192cc63aedb25cd99619174daa27902b10903" - integrity sha512-p52B+onAEHKW1OF9MGO/S7k/ahGEHfhP5/tvwYzog/5XLYOd8ZuD6vdNZdUuWMONRnKPneXV43v3s6Snx1wsCQ== +node-notifier@^5.4.2: + version "5.4.3" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.4.3.tgz#cb72daf94c93904098e28b9c590fd866e464bd50" + integrity sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q== dependencies: growly "^1.3.0" is-wsl "^1.1.0" @@ -6364,9 +6671,9 @@ node-pre-gyp@^0.12.0: tar "^4" node-releases@^1.1.25: - version "1.1.27" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.27.tgz#b19ec8add2afe9a826a99dceccc516104c1edaf4" - integrity sha512-9iXUqHKSGo6ph/tdXVbHFbhRVQln4ZDTIBJCzsa90HimnBYc5jw8RWYt4wBYFHehGyC3koIz5O4mb2fHrbPOuA== + version "1.1.28" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.28.tgz#503c3c70d0e4732b84e7aaa2925fbdde10482d4a" + integrity sha512-AQw4emh6iSXnCpDiFe0phYcThiccmkNWMZnFZ+lDJjAP8J0m2fVd59duvUUyuTirQOhIAajTFkzG6FHCLBO59g== dependencies: semver "^5.3.0" @@ -6467,7 +6774,7 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@4.1.1, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@4.1.1, object-assign@4.x, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -6589,13 +6896,6 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" -onetime@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.0.tgz#fff0f3c91617fe62bb50189636e99ac8a6df7be5" - integrity sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q== - dependencies: - mimic-fn "^2.1.0" - open@^6.3.0: version "6.4.0" resolved "https://registry.yarnpkg.com/open/-/open-6.4.0.tgz#5c13e96d0dc894686164f18965ecfe889ecfc8a9" @@ -6707,9 +7007,9 @@ p-limit@^1.1.0: p-try "^1.0.0" p-limit@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2" - integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ== + version "2.2.1" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" + integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== dependencies: p-try "^2.0.0" @@ -6869,6 +7169,13 @@ path-to-regexp@0.1.7: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= +path-to-regexp@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" + integrity sha1-Wf3g9DW62suhA6hOnTvGTpa5k30= + dependencies: + isarray "0.0.1" + path-type@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" @@ -6973,10 +7280,15 @@ pnp-webpack-plugin@1.5.0: dependencies: ts-pnp "^1.1.2" +popper.js@^1.14.4: + version "1.15.0" + resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.15.0.tgz#5560b99bbad7647e9faa475c6b8056621f5a4ff2" + integrity sha512-w010cY1oCUmI+9KwwlWki+r5jxKfTFDVoadl7MSrIujHU5MJ5OR6HTDj6Xo8aoR/QsA56x8jKjA59qGH4ELtrA== + portfinder@^1.0.9: - version "1.0.21" - resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.21.tgz#60e1397b95ac170749db70034ece306b9a27e324" - integrity sha512-ESabpDCzmBS3ekHbmpAIiESq3udRsCBGiBZLsC+HgBKv2ezb0R4oG+7RnYEVZ/ZCfhel5Tx3UzdNWA0Lox2QCA== + version "1.0.23" + resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.23.tgz#894db4bcc5daf02b6614517ce89cd21a38226b82" + integrity sha512-B729mL/uLklxtxuiJKfQ84WPxNw5a7Yhx3geQZdcA4GjNjZSTSSMMWyoennMVnTWSmAR0lMdzWYN0JLnHrg1KQ== dependencies: async "^1.5.2" debug "^2.2.0" @@ -7665,12 +7977,12 @@ pretty-error@^2.1.1: renderkid "^2.0.1" utila "~0.4" -pretty-format@^24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.8.0.tgz#8dae7044f58db7cb8be245383b565a963e3c27f2" - integrity sha512-P952T7dkrDEplsR+TuY7q3VXDae5Sr7zmQb12JU/NDQa/3CH7/QW0yvqLcGN6jL+zQFKaoJcPc+yJxMTGmosqw== +pretty-format@^24.9.0: + version "24.9.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" + integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== dependencies: - "@jest/types" "^24.8.0" + "@jest/types" "^24.9.0" ansi-regex "^4.0.0" ansi-styles "^3.2.0" react-is "^16.8.4" @@ -7707,6 +8019,13 @@ promise@8.0.3: dependencies: asap "~2.0.6" +promise@^7.1.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" + integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg== + dependencies: + asap "~2.0.3" + prompts@^2.0.1: version "2.2.1" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.2.1.tgz#f901dd2a2dfee080359c0e20059b24188d75ad35" @@ -7715,7 +8034,15 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.3" -prop-types@^15.6.2, prop-types@^15.7.2: +prop-types-extra@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/prop-types-extra/-/prop-types-extra-1.1.0.tgz#32609910ea2dcf190366bacd3490d5a6412a605f" + integrity sha512-QFyuDxvMipmIVKD2TwxLVPzMnO4e5oOf1vr3tJIomL8E7d0lr6phTHd5nkPhFIzTD1idBLLEPeylL9g+rrTzRg== + dependencies: + react-is "^16.3.2" + warning "^3.0.0" + +prop-types@15.x, prop-types@^15.3.0, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -7824,7 +8151,7 @@ querystringify@^2.1.1: resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e" integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA== -raf@3.4.1: +raf@3.4.1, raf@^3.4.0: version "3.4.1" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== @@ -7861,6 +8188,51 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" +rc-animate@^2.9.2: + version "2.9.2" + resolved "https://registry.yarnpkg.com/rc-animate/-/rc-animate-2.9.2.tgz#5964767805c886f1bdc7563d3935a74912a0b78f" + integrity sha512-rkJjeJgfbDqVjVX1/QTRfS7PiCq3AnmeYo840cVcuC4pXq4k4yAQMsC2v5BPXXdawC04vnyO4/qHQdbx9ANaiw== + dependencies: + babel-runtime "6.x" + classnames "^2.2.6" + css-animation "^1.3.2" + prop-types "15.x" + raf "^3.4.0" + rc-util "^4.8.0" + react-lifecycles-compat "^3.0.4" + +rc-tree@^3.0.0-alpha.15: + version "3.0.0-alpha.15" + resolved "https://registry.yarnpkg.com/rc-tree/-/rc-tree-3.0.0-alpha.15.tgz#ffb662e46e510aa40e128cef00fa6a14964eef9a" + integrity sha512-/xHvMQdvwpze0Qs0wOKjD8ZJRyn9mm/CFuIFr56jD90ZCBmzyJ8pFfM2MIq3qrneVNNI9kLU3XSk1J0Ku+4MYw== + dependencies: + classnames "2.x" + prop-types "^15.5.8" + rc-animate "^2.9.2" + rc-util "^4.9.0" + rc-virtual-list "^0.0.0-alpha.18" + react-lifecycles-compat "^3.0.4" + warning "^4.0.3" + +rc-util@^4.8.0, rc-util@^4.9.0: + version "4.11.0" + resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-4.11.0.tgz#cf437dcff74ca08a8565ae14f0368acb3a650796" + integrity sha512-nB29kXOXsSVjBkWfH+Z1GVh6tRg7XGZtZ0Yfie+OI0stCDixGQ1cPrS6iYxlg+AV2St6COCK5MFrCmpTgghh0w== + dependencies: + add-dom-event-listener "^1.1.0" + babel-runtime "6.x" + prop-types "^15.5.10" + react-lifecycles-compat "^3.0.4" + shallowequal "^0.2.2" + +rc-virtual-list@^0.0.0-alpha.18: + version "0.0.0-alpha.23" + resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-0.0.0-alpha.23.tgz#d22fbcba9a4b359f4e099b5d2d0557c6c15531a0" + integrity sha512-s4pjXAarPvGlWxyKc+UKdsy25Ocfkx/OU9ds84KMB5D//aq+AFKpIhNvZd7iylCk/Zh3wxvoScntuh0wWV+h9g== + dependencies: + classnames "^2.2.6" + rc-util "^4.8.0" + rc@^1.2.7: version "1.2.8" resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" @@ -7883,6 +8255,20 @@ react-app-polyfill@^1.0.2: regenerator-runtime "0.13.3" whatwg-fetch "3.0.0" +react-context-toolbox@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/react-context-toolbox/-/react-context-toolbox-2.0.2.tgz#35637287cb23f801e6ed802c2bb7a97e1f04e3fb" + integrity sha512-tY4j0imkYC3n5ZlYSgFkaw7fmlCp3IoQQ6DxpqeNHzcD0hf+6V+/HeJxviLUZ1Rv1Yn3N3xyO2EhkkZwHn0m1A== + +react-cookie@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/react-cookie/-/react-cookie-4.0.1.tgz#c21b2c30a5cacf320b45338fa3dcaf76d9fe9c2c" + integrity sha512-h61qAtSXvfjNa81h3XCFdFoyFaF+nb7gjK0cxQuTiCPMPAe50D950FjLCFhaIfSpAesQFAmkxf5XFpWoEVBDAA== + dependencies: + "@types/hoist-non-react-statics" "^3.0.1" + hoist-non-react-statics "^3.0.0" + universal-cookie "^4.0.0" + react-dev-utils@^9.0.3: version "9.0.3" resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-9.0.3.tgz#7607455587abb84599451460eb37cef0b684131a" @@ -7914,7 +8300,7 @@ react-dev-utils@^9.0.3: strip-ansi "5.2.0" text-table "0.2.0" -react-dom@16.9.0: +react-dom@^16.9.0: version "16.9.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.9.0.tgz#5e65527a5e26f22ae3701131bcccaee9fb0d3962" integrity sha512-YFT2rxO9hM70ewk9jq0y6sQk8cL02xm4+IzYBz75CQGlClQQ1Bxq0nhHF6OtSbit+AIahujJgb/CPRibFkMNJQ== @@ -7929,11 +8315,123 @@ react-error-overlay@^6.0.1: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.1.tgz#b8d3cf9bb991c02883225c48044cb3ee20413e0f" integrity sha512-V9yoTr6MeZXPPd4nV/05eCBvGH9cGzc52FN8fs0O0TVQ3HYYf1n7EgZVtHbldRq5xU9zEzoXIITjYNIfxDDdUw== -react-is@^16.8.1, react-is@^16.8.4: +react-fast-compare@^2.0.2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" + integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== + +react-ga@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/react-ga/-/react-ga-2.6.0.tgz#c3fe830ead2ad25117e1d33280d9698de9b28496" + integrity sha512-GWHBWZDFjDGMkIk1LzroIn0mNTygKw3adXuqvGvheFZvlbpqMPbHsQsTdQBIxRRdXGQM/Zq+dQLRPKbwIHMTaw== + +react-helmet@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-5.2.1.tgz#16a7192fdd09951f8e0fe22ffccbf9bb3e591ffa" + integrity sha512-CnwD822LU8NDBnjCpZ4ySh8L6HYyngViTZLfBBb3NjtrpN8m49clH8hidHouq20I51Y6TpCTISCBbqiY5GamwA== + dependencies: + object-assign "^4.1.1" + prop-types "^15.5.4" + react-fast-compare "^2.0.2" + react-side-effect "^1.1.0" + +react-html-parser@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/react-html-parser/-/react-html-parser-2.0.2.tgz#6dbe1ddd2cebc1b34ca15215158021db5fc5685e" + integrity sha512-XeerLwCVjTs3njZcgCOeDUqLgNIt/t+6Jgi5/qPsO/krUWl76kWKXMeVs2LhY2gwM6X378DkhLjur0zUQdpz0g== + dependencies: + htmlparser2 "^3.9.0" + +react-image-lightbox@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/react-image-lightbox/-/react-image-lightbox-5.1.0.tgz#b47b904b027c918acdd9efa94dc0a0ddd8125c86" + integrity sha512-R46QvffoDBscLQgTl4s3kFxVbnP7a+nIh7AXJNS0EXVeDaa6zKDKtIT+jFeEvs+F9oUHtZfenG1NHhTkO4hEOA== + dependencies: + prop-types "^15.6.2" + react-modal "^3.6.1" + +react-is@^16.3.2, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4: version "16.9.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.9.0.tgz#21ca9561399aad0ff1a7701c01683e8ca981edcb" integrity sha512-tJBzzzIgnnRfEm046qRcURvwQnZVXmuCbscxUO5RWrGTXpon2d4c8mI0D8WE6ydVIm29JiLB6+RslkIvym9Rjw== +react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + +react-modal@^3.6.1: + version "3.10.1" + resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.10.1.tgz#ba37927871830c798f51404aa6bc71ff7a5e4c16" + integrity sha512-2DKIfdOc8+WY+SYJ/xf/WBwOYMmNAYAyGkYlc4e1TCs9rk1xY4QBz04hB3UHGcrLChh7ce77rHAe6VPNmuLYsQ== + dependencies: + exenv "^1.2.0" + prop-types "^15.5.10" + react-lifecycles-compat "^3.0.0" + warning "^4.0.3" + +react-overlays@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/react-overlays/-/react-overlays-1.2.0.tgz#205368eeb0a5fb0b7f9b717fa7a12d518500abdb" + integrity sha512-i/FCV8wR6aRaI+Kz/dpJhOdyx+ah2tN1RhT9InPrexyC4uzf3N4bNayFTGtUeQVacj57j1Mqh1CwV60/5153Iw== + dependencies: + classnames "^2.2.6" + dom-helpers "^3.4.0" + prop-types "^15.6.2" + prop-types-extra "^1.1.0" + react-context-toolbox "^2.0.2" + react-popper "^1.3.2" + uncontrollable "^6.0.0" + warning "^4.0.2" + +react-popper@^1.3.2: + version "1.3.4" + resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-1.3.4.tgz#f0cd3b0d30378e1f663b0d79bcc8614221652ced" + integrity sha512-9AcQB29V+WrBKk6X7p0eojd1f25/oJajVdMZkywIoAV6Ag7hzE1Mhyeup2Q1QnvFRtGQFQvtqfhlEoDAPfKAVA== + dependencies: + "@babel/runtime" "^7.1.2" + create-react-context "^0.3.0" + popper.js "^1.14.4" + prop-types "^15.6.1" + typed-styles "^0.0.7" + warning "^4.0.2" + +react-router-dom@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.0.1.tgz#ee66f4a5d18b6089c361958e443489d6bab714be" + integrity sha512-zaVHSy7NN0G91/Bz9GD4owex5+eop+KvgbxXsP/O+iW1/Ln+BrJ8QiIR5a6xNPtrdTvLkxqlDClx13QO1uB8CA== + dependencies: + "@babel/runtime" "^7.1.2" + history "^4.9.0" + loose-envify "^1.3.1" + prop-types "^15.6.2" + react-router "5.0.1" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + +react-router-hash-link@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/react-router-hash-link/-/react-router-hash-link-1.2.2.tgz#7a0ad5e925d49596d19554de8bc6c554ce4f8099" + integrity sha512-LBthLVHdqPeKDVt3+cFRhy15Z7veikOvdKRZRfyBR2vjqIE7rxn+tKLjb6DOmLm6JpoQVemVDnxQ35RVnEHdQA== + dependencies: + prop-types "^15.6.0" + +react-router@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.0.1.tgz#04ee77df1d1ab6cb8939f9f01ad5702dbadb8b0f" + integrity sha512-EM7suCPNKb1NxcTZ2LEOWFtQBQRQXecLxVpdsP4DW4PbbqYWeRiLyV/Tt1SdCrvT2jcyXAXmVTmzvSzrPR63Bg== + dependencies: + "@babel/runtime" "^7.1.2" + history "^4.9.0" + hoist-non-react-statics "^3.1.0" + loose-envify "^1.3.1" + mini-create-react-context "^0.3.0" + path-to-regexp "^1.7.0" + prop-types "^15.6.2" + react-is "^16.6.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + react-scripts@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-3.1.1.tgz#1796bc92447f3a2d3072c3b71ca99f88d099c48d" @@ -7995,7 +8493,30 @@ react-scripts@3.1.1: optionalDependencies: fsevents "2.0.7" -react@16.9.0: +react-side-effect@^1.1.0: + version "1.1.5" + resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-1.1.5.tgz#f26059e50ed9c626d91d661b9f3c8bb38cd0ff2d" + integrity sha512-Z2ZJE4p/jIfvUpiUMRydEVpQRf2f8GMHczT6qLcARmX7QRb28JDBTpnM2g/i5y/p7ZDEXYGHWg0RbhikE+hJRw== + dependencies: + exenv "^1.2.1" + shallowequal "^1.0.1" + +react-spinner-material@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/react-spinner-material/-/react-spinner-material-1.1.3.tgz#bdf375089f038028250762007323f026de5f57d5" + integrity sha512-sa9ESbt9/V79jzdxYGfd0i84JG5Nuz6q2wmxqS0Jc8M+J/Rk/aHiA/R2X1ewAwRxysMMDhFG7Altf7FEea1vkg== + +react-twitter-widgets@^1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/react-twitter-widgets/-/react-twitter-widgets-1.7.1.tgz#60061f37a8c4f361c27f3d1d7ceba98d3cd80a40" + integrity sha512-bAcR/NKqRbVRJav981bHrm2+xka7NA2nQJB6Urtj9BARqP7aeGHPC0CrrC7wdYIaluOqiF8MiTtURqIJjFs2ZA== + dependencies: + exenv "^1.2.1" + lodash "^4.17.4" + prop-types "^15.3.0" + scriptjs "^2.5.8" + +react@^16.9.0: version "16.9.0" resolved "https://registry.yarnpkg.com/react/-/react-16.9.0.tgz#40ba2f9af13bc1a38d75dbf2f4359a5185c4f7aa" integrity sha512-+7LQnFBwkiw+BobzOF6N//BdoNw0ouwmSJTEm9cglOOmsg/TMiFHZLe2sEoN5M7LgJTj9oHH0gxklfnQe66S1w== @@ -8126,9 +8647,9 @@ regex-parser@2.2.10: integrity sha512-8t6074A68gHfU8Neftl0Le6KTDwfGAj7IyjPIMSfikI2wJUTHDMaIq42bUsfVnj8mhx0R+45rdUXHGpN164avA== regexp-tree@^0.1.6: - version "0.1.11" - resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.11.tgz#c9c7f00fcf722e0a56c7390983a7a63dd6c272f3" - integrity sha512-7/l/DgapVVDzZobwMCCgMlqiqyLFJ0cduo/j+3BcDJIB+yJdsYCfKuI3l/04NV+H/rfNRdPIDbXNZHM9XvQatg== + version "0.1.12" + resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.12.tgz#28eaaa6e66eeb3527c15108a3ff740d9e574e420" + integrity sha512-TsXZ8+cv2uxMEkLfgwO0E068gsNMLfuYwMMhiUxf0Kw2Vcgzq93vgl6wIlIYuPmfMqMjfQ9zAporiozqCnwLuQ== regexpp@^2.0.1: version "2.0.1" @@ -8206,7 +8727,7 @@ request-promise-native@^1.0.5: stealthy-require "^1.1.1" tough-cookie "^2.3.3" -request@^2.87.0, request@^2.88.0: +request@^2.83.0, request@^2.87.0, request@^2.88.0: version "2.88.0" resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== @@ -8269,6 +8790,11 @@ resolve-from@^4.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== +resolve-pathname@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-2.2.0.tgz#7e9ae21ed815fd63ab189adeee64dc831eefa879" + integrity sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg== + resolve-url-loader@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/resolve-url-loader/-/resolve-url-loader-3.1.0.tgz#54d8181d33cd1b66a59544d05cadf8e4aa7d37cc" @@ -8310,14 +8836,6 @@ restore-cursor@^2.0.0: onetime "^2.0.0" signal-exit "^3.0.2" -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - ret@~0.1.10: version "0.1.15" resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" @@ -8346,13 +8864,20 @@ rgba-regex@^1.0.0: resolved "https://registry.yarnpkg.com/rgba-regex/-/rgba-regex-1.0.0.tgz#43374e2e2ca0968b0ef1523460b7d730ff22eeb3" integrity sha1-QzdOLiyglosO8VI0YLfXMP8i7rM= -rimraf@2.6.3, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3: +rimraf@2.6.3: version "2.6.3" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== dependencies: glob "^7.1.3" +rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" @@ -8472,6 +8997,11 @@ schema-utils@^2.0.0, schema-utils@^2.0.1: ajv "^6.1.0" ajv-keywords "^3.1.0" +scriptjs@^2.5.8: + version "2.5.9" + resolved "https://registry.yarnpkg.com/scriptjs/-/scriptjs-2.5.9.tgz#343915cd2ec2ed9bfdde2b9875cd28f59394b35f" + integrity sha512-qGVDoreyYiP1pkQnbnFAUIS5AjenNwwQBdl7zeos9etl+hYKWahjRTfzAZZYBv5xNHx7vNKCmaLDQZ6Fr2AEXg== + select-hose@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" @@ -8494,7 +9024,7 @@ semver@5.5.0: resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" integrity sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA== -semver@6.3.0, semver@^6.0.0, semver@^6.1.2, semver@^6.3.0: +semver@6.3.0, semver@^6.0.0, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== @@ -8519,9 +9049,9 @@ send@0.17.1: statuses "~1.5.0" serialize-javascript@^1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.7.0.tgz#d6e0dfb2a3832a8c94468e6eb1db97e55a192a65" - integrity sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA== + version "1.8.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.8.0.tgz#9515fc687232e2321aea1ca7a529476eb34bb480" + integrity sha512-3tHgtF4OzDmeKYj6V9nSyceRS0UJ3C7VqyD2Yj28vC/z2j6jG5FmFGahOKMD9CrglxTm3tETr87jEypaYV8DUg== serve-index@^1.7.2: version "1.9.1" @@ -8601,6 +9131,18 @@ shallow-clone@^3.0.0: dependencies: kind-of "^6.0.2" +shallowequal@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-0.2.2.tgz#1e32fd5bcab6ad688a4812cb0cc04efc75c7014e" + integrity sha1-HjL9W8q2rWiKSBLLDMBO/HXHAU4= + dependencies: + lodash.keys "^3.1.2" + +shallowequal@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" + integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -8921,7 +9463,7 @@ string-width@^1.0.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string-width@^3.0.0: +string-width@^3.0.0, string-width@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== @@ -8930,15 +9472,6 @@ string-width@^3.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" -string-width@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.1.0.tgz#ba846d1daa97c3c596155308063e075ed1c99aff" - integrity sha512-NrX+1dVVh+6Y9dnQ19pR0pP4FiEIlUvdTGn8pw6CKTNq5sgib2nIhmUNT5TAmhWmvKr3WcxBcP3E8nWezuipuQ== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^5.2.0" - string_decoder@^1.0.0, string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -9077,9 +9610,9 @@ symbol-tree@^3.2.2: integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== table@^5.2.3: - version "5.4.5" - resolved "https://registry.yarnpkg.com/table/-/table-5.4.5.tgz#c8f4ea2d8fee08c0027fac27b0ec0a4fe01dfa42" - integrity sha512-oGa2Hl7CQjfoaogtrOHEJroOcYILTx7BZWLGsJIlzoWmB2zmguhNfPJZsWPKYek/MgCxfco54gEi31d1uN2hFA== + version "5.4.6" + resolved "https://registry.yarnpkg.com/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" + integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== dependencies: ajv "^6.10.2" lodash "^4.17.14" @@ -9120,9 +9653,9 @@ terser-webpack-plugin@1.4.1, terser-webpack-plugin@^1.4.1: worker-farm "^1.7.0" terser@^4.1.2: - version "4.1.4" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.1.4.tgz#4478b6a08bb096a61e793fea1a4434408bab936c" - integrity sha512-+ZwXJvdSwbd60jG0Illav0F06GDJF0R4ydZ21Q3wGAFKoBGyJGo34F63vzJHgvYxc1ukOtIjvwEvl9MkjzM6Pg== + version "4.2.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-4.2.1.tgz#1052cfe17576c66e7bc70fcc7119f22b155bdac1" + integrity sha512-cGbc5utAcX4a9+2GGVX4DsenG6v0x3glnDi5hx8816X1McEAwPlPgRtXPJzSBsbpILxZ8MQMT0KvArLuE0HP5A== dependencies: commander "^2.20.0" source-map "~0.6.1" @@ -9178,6 +9711,16 @@ timsort@^0.3.0: resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= +tiny-invariant@^1.0.2: + version "1.0.6" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.0.6.tgz#b3f9b38835e36a41c843a3b0907a5a7b3755de73" + integrity sha512-FOyLWWVjG+aC0UqG76V53yAWdXfH8bO6FNmyZOuUrzDzK8DI3/JRY25UD7+g49JWM1LXwymsKERB+DzI0dTEQA== + +tiny-warning@^1.0.0, tiny-warning@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" + integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -9299,11 +9842,6 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-fest@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.5.2.tgz#d6ef42a0356c6cd45f49485c3b6281fc148e48a2" - integrity sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw== - type-is@~1.6.17, type-is@~1.6.18: version "1.6.18" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" @@ -9317,6 +9855,11 @@ type@^1.0.1: resolved "https://registry.yarnpkg.com/type/-/type-1.0.3.tgz#16f5d39f27a2d28d86e48f8981859e9d3296c179" integrity sha512-51IMtNfVcee8+9GJvj0spSuFcZHe9vSib6Xtgsny1Km9ugyz2mbS08I3rsUIRYgJohFRFU1160sgRodYz378Hg== +typed-styles@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/typed-styles/-/typed-styles-0.0.7.tgz#93392a008794c4595119ff62dde6809dbc40a3d9" + integrity sha512-pzP0PWoZUhsECYjABgCGQlRGL1n7tOHsgwYv3oIiEpJwGhFTuty/YNeduxQYzXXa3Ge5BdT6sHYIQYpl4uJ+5Q== + typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" @@ -9343,6 +9886,14 @@ uglify-js@^3.1.4: commander "~2.20.0" source-map "~0.6.1" +uncontrollable@^6.0.0: + version "6.2.3" + resolved "https://registry.yarnpkg.com/uncontrollable/-/uncontrollable-6.2.3.tgz#e7dba0d746e075122ed178f27ad2354d343196c7" + integrity sha512-VgOAoBU2ptCL2bfTG2Mra0I8i1u6Aq84AFonD5tmCAYSfs3hWvr2Rlw0q2ntoxXTHjcQOmZOh3FKaN+UZVyREQ== + dependencies: + "@babel/runtime" "^7.4.5" + invariant "^2.2.4" + unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" @@ -9400,6 +9951,16 @@ unique-slug@^2.0.0: dependencies: imurmurhash "^0.1.4" +universal-cookie@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/universal-cookie/-/universal-cookie-4.0.2.tgz#c3398a64c72ff0c31fecb1ac4966c424e8669c6d" + integrity sha512-n14lhA//lQeYRweP9j9uXsshN9Cs4LunVSnvAGmnA69SofwsjpUU03geaCaPC9LlsH2rkBy99o3zxQyVOldGvA== + dependencies: + "@types/cookie" "^0.3.3" + "@types/object-assign" "^4.0.30" + cookie "^0.4.0" + object-assign "^4.1.1" + universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -9513,9 +10074,9 @@ utils-merge@1.0.1: integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= uuid@^3.0.1, uuid@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" - integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== + version "3.3.3" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" + integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ== v8-compile-cache@^2.0.3: version "2.1.0" @@ -9530,6 +10091,11 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" +value-equal@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-0.4.0.tgz#c5bdd2f54ee093c04839d71ce2e4758a6890abc7" + integrity sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw== + vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -9577,6 +10143,20 @@ walker@^1.0.7, walker@~1.0.5: dependencies: makeerror "1.0.x" +warning@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c" + integrity sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w= + dependencies: + loose-envify "^1.0.0" + +warning@^4.0.2, warning@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" + integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== + dependencies: + loose-envify "^1.0.0" + watchpack@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00" @@ -9933,6 +10513,15 @@ wrap-ansi@^2.0.0: string-width "^1.0.1" strip-ansi "^3.0.1" +wrap-ansi@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" + integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== + dependencies: + ansi-styles "^3.2.0" + string-width "^3.0.0" + strip-ansi "^5.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -9983,6 +10572,13 @@ xregexp@4.0.0: resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.0.0.tgz#e698189de49dd2a18cc5687b05e17c8e43943020" integrity sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg== +xregexp@^4.2.4: + version "4.2.4" + resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-4.2.4.tgz#02a4aea056d65a42632c02f0233eab8e4d7e57ed" + integrity sha512-sO0bYdYeJAJBcJA8g7MJJX7UrOZIfJPd8U2SC7B2Dd/J24U0aQNoGp33shCaBSWeb0rD5rh6VBUIXOkGal1TZA== + dependencies: + "@babel/runtime-corejs2" "^7.2.0" + xtend@^4.0.0, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" @@ -10005,10 +10601,10 @@ yargs-parser@^10.1.0: dependencies: camelcase "^4.1.0" -yargs-parser@^11.1.1: - version "11.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" - integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== +yargs-parser@^13.1.1: + version "13.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" + integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== dependencies: camelcase "^5.0.0" decamelize "^1.2.0" @@ -10031,20 +10627,18 @@ yargs@12.0.2: y18n "^3.2.1 || ^4.0.0" yargs-parser "^10.1.0" -yargs@^12.0.2: - version "12.0.5" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" - integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== +yargs@^13.3.0: + version "13.3.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83" + integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA== dependencies: - cliui "^4.0.0" - decamelize "^1.2.0" + cliui "^5.0.0" find-up "^3.0.0" - get-caller-file "^1.0.1" - os-locale "^3.0.0" + get-caller-file "^2.0.1" require-directory "^2.1.1" - require-main-filename "^1.0.1" + require-main-filename "^2.0.0" set-blocking "^2.0.0" - string-width "^2.0.0" + string-width "^3.0.0" which-module "^2.0.0" - y18n "^3.2.1 || ^4.0.0" - yargs-parser "^11.1.1" + y18n "^4.0.0" + yargs-parser "^13.1.1"